13 Operaattoreiden ylimäärittelyjä



Samankaltaiset tiedostot
14. oppitunti. Operaattorin ylikuormitus. Osa. Operaattorin ylikuormittaminen

12 Mallit (Templates)

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Olio-ohjelmointi 2. välikoe HYV5SN

Tietotyypit ja operaattorit

Olio-ohjelmointi Syntaksikokoelma

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

C++ rautaisannos. Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout:

Luokassa määriteltävät jäsenet ovat pääasiassa tietojäseniä tai aliohjelmajäseniä. Luokan määrittelyyn liittyvät varatut sanat:

Ohjelmointi 1 Taulukot ja merkkijonot

Ohjelmoinnin perusteet Y Python

T Olio-ohjelmointi Osa 3: Luokka, muodostin ja hajotin, this-osoitin Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

Tehtävä 1. TL5302 Olio-ohjelmointi Koe Malliratkaisuja. Tässä sekä a)- että b)-kohdan toimiva ratkaisu:

Plagioinnin tunnistaminen lähdekielisistä ohjelmista

Ohjelmointi 2. Jussi Pohjolainen. TAMK» Tieto- ja viestintäteknologia , Jussi Pohjolainen TAMPEREEN AMMATTIKORKEAKOULU

Osoitin ja viittaus C++:ssa

11. oppitunti III. Viittaukset. Osa. Mikä on viittaus?

VIII. Osa. Liitteet. Liitteet Suoritusjärjestys Varatut sanat Binääri- ja heksamuoto

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Tietueet. Tietueiden määrittely

Operaattoreiden uudelleenmäärittely

Demo 6 vastauksia. 1. tehtävä. #ifndef #define D6T1 H D6T1 H. #include <iostream> using std::ostream; using std::cout; using std::endl;

Java-kielen perusteet

Muuttujien roolit Kiintoarvo cin >> r;

Osa III. Olioiden luominen vapaalle muistialueelle

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

5.6. C-kielen perusteet, osa 6/8, Taulukko , pva, kuvat jma

Metodien tekeminen Javalla

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

Java-kielen perusteet

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Kompositio. Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma

Olio-ohjelmointi Javalla

Mallit standardi mallikirjasto parametroitu tyyppi

Mikä yhteyssuhde on?

Java-kielen perusteet

tietueet eri tyyppisiä tietoja saman muuttujan arvoiksi

Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö C-ohjelmassa

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

21. oppitunti. Esikäsittelijä. Osa. Esikäsittelijä ja kääntäjä

Virtuaalifunktiot ja polymorfismi

Ohjelmoinnin perusteet Y Python

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Johdatus ohjelmointiin / Lausekielinen ohjelmointi 1 & 2

Taulukot. Taulukon määrittely ja käyttö. Taulukko metodin parametrina. Taulukon sisällön kopiointi toiseen taulukkoon. Taulukon lajittelu

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

Tietorakenteet ja algoritmit

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Sisältö. 22. Taulukot. Yleistä. Yleistä

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

C++11 Syntaksi. Jari-Pekka Voutilainen Jari-Pekka Voutilainen: C++11 Syntaksi

Geneeriset luokat. C++ - perusteet Java-osaajille luento 6/7: Template, tyyppi-informaatio, nimiavaruudet. Geneerisen luokan käyttö.

Ohjelmoinnin peruskurssi Y1

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

Ohjelmoinnin perusteet Y Python

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Ohjelmoinnin perusteet Y Python

15. oppitunti. Taulukot. Osa. Mikä on taulukko?

7. Näytölle tulostaminen 7.1

Taulukot. Jukka Harju, Jukka Juslin

Osoittimet. Mikä on osoitin?

2 Haku ja lajittelu. 2.1 Luvun hakeminen taulukosta X?? n-1. Haku ja lajittelu 35

ELEC-A4010 Sähköpaja Arduinon ohjelmointi. Jukka Helle

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Osa. Mikä on linkitetty lista Kuinka linkitetty lista luodaan Kuinka toiminnallisuus kapseloidaan periytymisen kautta

Osa. Erikoisaiheet. Oppitunnit 20 Erikoisluokat ja -funktiot 21 Esikäsittelijä

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Ohjelmoinnin jatkokurssi, kurssikoe

Harjoitustyö: virtuaalikone

Osa IV. Oliokeskeinen ohjelmointi

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Ohjelmointi 2 / 2008 Välikoe / Pöytätestaa seuraava ohjelma.

TIETORAKENTEET JA ALGORITMIT

Kääntäjän virheilmoituksia

Muuttujatyypit ovat Boolean, Byte, Integer, Long, Double, Currency, Date, Object, String, Variant (oletus)

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

\+jokin merkki tarkoittaa erikoismerkkiä; \n = uusi rivi.

Osa VII. Mitä mallit ovat ja kuinka niitä käytetään Miksi mallit tarjoavat paremman vaihtoehdon makroille Kuinka luokkamalleja luodaan

Sisältö. 2. Taulukot. Yleistä. Yleistä

Javan perusteita. Janne Käki

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

UML ja luokkien väliset suhteet

Algoritmit 1. Demot Timo Männikkö

Osa III. Edelliset kolme lukua ovat käsitelleet viittausten ja osoittimien käyttöä. Tämän luvun aiheita ovat:

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Algoritmit C++ Kauko Kolehmainen

1. Omat operaatiot 1.1

T Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

Java kahdessa tunnissa. Jyry Suvilehto

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

15. Ohjelmoinnin tekniikkaa 15.1

Listarakenne (ArrayList-luokka)

Ohjelmointiharjoituksia Arduino-ympäristössä

Lyhyt kertaus osoittimista

Merkkijonot ja C++ Antti-Juhani Kaijanaho. 5. maaliskuuta Vanhojen C++-kääntäjien käyttäjät, huomio! 2 Merkkijonojen perusteet

Transkriptio:

248 13 C++-kielessä voidaan operaattoreita ylimäärittää. Ylimääriteltävää operaattoria voidaan pitää ikäänkuin metodina, joka esitellään luokan esittelyssä ja määritellään luokan ulkopuolella kuten metoditkin. Ylimääritellyillä operaattoreilla on kuitenkin poikkeavat nimet ja vain olemassaolevia operaattoreita voidaan ylimääritellä. C++-kielessä käytetään operaattoreiden ylimäärittelyjä muutoinkin: esimerkiksi yhteenlaskuoperaattori (+) on ylimääritelty laskemaan yhteen kokonaislukuja ja liukulukuja, vaikka niiden talletustavat ovat erilaiset. Sisäisten tietotyyppien operaattoreita ei voida ylimääritellä. Muissa kielissä saatetaan ylimäärittelyssä mennä vieläkin pitemmälle: esimerkiksi Java-kielessä voidaan +-operaattorilla yhdistää merkkijonoja. C++-kielessä voidaan ylimääritellä seuraavia operaattoreita: new delete + - * & = / % ^ ~! < > << >> ==!= += -= *= /= %= ^= &= = ->* &&, ++ -- -> () [] Esittelyssä ja määrittelyssä käytetään avainsanaa operator, jota seuraa ylimääriteltävä operaattori. Operaattorin ylimäärittely voidaan toteuttaa metodin tai ystävä-funktion kautta. Binääreillä operaattoreilla on aina 1 parametri ja unaareilla ei ole parametria lainkaan silloin, kun operaattorit on ylimääritelty luokan jäseninä. 13.1 Operaattorin + ylimäärittely Seuraavassa ylimääritellään yhteenlaskuoperaattori laskemaan yhteen kaksi kompleksilukua. Jäsenmuuttujat vastaavat kompleksiluvun reaali- ja imaginääriosia. Ylimäärittelyn toteuttavan funktion määrittely on seuraavanlainen:

249 operator+ complex operator+ (const complex a, const complex b) complex temp(0,0); temp.x = b.x + a.x; temp.y = b.y + a.y; return temp; Parametreina on kaksi vakiota complex-oliota ja palautusarvona on olio, jonka jäsenmuuttujina ovat parametreina vietyjen olioiden jäsenmuuttujien summat. Nyt yhteenlaskuoperaattorin operandeina voi olla olioita: complex c=a+b; Ylimääritelty operator+ ohjelmassa: class complex double x, y; complex (double real, double imag) x=real; y=imag; friend complex operator+ (const complex a, const complex b); friend void main(); ; complex operator+ (const complex a, const complex b) complex temp(0,0); temp.x = b.x + a.x; temp.y = b.y + a.y; return temp; void main() complex a(2,3); cout << a.x << a.y << "\n"; complex b(1,1); complex c=a+b; cout << a.x << a.y << "\n";

250 cout << b.x << b.y << "\n"; cout << c.x << c.y << "\n"; Kun operaattori esitellään luokan metodina, on yleensä operaattorilla vain yksi parametri. Seuraavassa esimerkissä käytetään yhteenlaskuoperaattoria luokan jäsenenä. operator+ ohjelmassa luokan jäsenenä: typedef unsigned short USHORT; class Laskuri Laskuri (); ~ Laskuri () USHORT HaeArvo()const return arvo; void AsetaArvo(USHORT x) arvo = x; Laskuri operator+ (const Laskuri &); private: USHORT arvo; ; Laskuri:: Laskuri (): arvo(0) ; Laskuri & Laskuri::operator+(const Laskuri & oikeapuoli) return Laskuri(arvo + oikeapuoli.haearvo()); int main() Laskuri L; Laskuri eka, toka, kolkku; eka.asetaarvo(4); toka.asetaarvo(5); kolkku = eka + toka; cout << kolkku.haearvo(); return 0;

251 Seuraavassa ohjelmassa on ylimääritelty +-operaattori muuttamaan penneinä annettu rahasumma markoiksi ja penneiksi. Ohjelmassa on myös erikoismuodostin, joka muuntaa parametrinä viedyn pennisumman olioksi, jonka jäsenmuuttujiin sijoitetaan vastaavat markka- ja pennimäärät. operator+ ja muunnosmuodostin: class Raha int markat; int pennit; Raha() ~Raha() Raha(int); Raha operator+(raha R); ; // muunnos double-tyypistä // operaattorin uudelleenmäärittely Raha Raha::operator+(Raha R) pennit += R.pennit; markat += R.markat; markat = pennit / 100; pennit = pennit % 100; return *this; Raha::Raha(int pennisumma) // muunnosmuodostin muuntaa int-tyypin Raha-olioksi markat = pennisumma / 100; pennit = pennisumma % 100; int main() int a, b; int pennit1 = 550; int pennit2 = 220; Raha lompakko = pennit1 + pennit2;

252 a = lompakko.markat; b = lompakko.pennit; cout << "Lompsassasi on nyt " << a << " markkaa\n"; cout << "Sekä " << b << " penniä\n"; return 0; Seuraavana on ylimääriteltynä operaattori +=, joka esitellään luokkaan kuuluvana operaattorina: operator += complex complex:: operator+= (const complex p) x += p.x; y += p.y; return *this; operator += ohjelmassa: class complex double x, y; complex (double real, double imag) x=real; y=imag; complex operator+= (const complex p); friend void main(); ; complex complex:: operator+= (const complex p) x += p.x; y += p.y; return *this; void main() complex a(2,3);

cout << a.x << a.y << "\n"; complex b(1,1); a+=b; cout << a.x << a.y << "\n"; cout << b.x << b.y << "\n"; 253 13.2 Jakolaskuoperaattori (/) Seuraavana on ohjelma, jossa Murtoluku-luokan jäsenmuuttujina ovat jakaja ja jaettava ja ylimääritelty jakolaskuoperaattori (/) on määritelty toteuttamaan kahden murtolukuolion jakolasku: operator/ class Murtoluku int jakaja; int jaettava; Murtoluku(); Murtoluku(int a, int b)jakaja = b;jaettava = a; friend main(); friend Murtoluku operator /(Murtoluku& c1, Murtoluku& c2); friend void Sievenna(Murtoluku & c1); ; Murtoluku::Murtoluku() jakaja = 0; jaettava = 0; void Sievenna(Murtoluku & c1) int syt; int a = c1.jakaja; int b = c1.jaettava; while (a!= b) if (a > b) a = a-b;

254 else b = b-a; syt=a; c1.jakaja = c1.jakaja/syt; c1.jaettava = c1.jaettava/syt; Murtoluku operator /(Murtoluku& c1, Murtoluku& c2) Murtoluku tulos; tulos.jakaja = c1.jaettava * c2.jakaja; tulos.jaettava = c2.jaettava * c1.jakaja; return tulos; main() int p; Murtoluku Luku1(2,3); Murtoluku Luku2(5,6); Murtoluku Luku3 = Luku1/Luku2; // 2/3 : 5/6 = 2/3 * 6/5 = 12/15 cout << "3. murtoluvun jakaja on " << Luku3.jakaja << "\n"; cout << "3. murtoluvun jaettava on " << Luku3.jaettava << "\n"; Sievenna(Luku3); cout << "3. murtoluvun jakaja on " << Luku3.jakaja << "\n"; cout << "3. murtoluvun jaettava on " << Luku3.jaettava << "\n"; return 0; Sijoitusoperaattori (=) tulee ylimääritellä esimerkiksi silloin, kun jäsenmuuttujina on osoittimia. Tällöin sijoitusoperaattorin tulee huolehtia siitä, että osoittimissa olevat muistiosoitteet ovat uniikkeja. Sijoitusoperaattori samoin kuin hakasulkuoperaattorikin tulee esitellä luokan jäsenenä. Myös ns. funktion kutsu -operaattori () tulee esitellä jäsenenä. 13.3 operator++ Kasvatusoperaattori voidaan myöskin ylimääritellä toimimaan halutulla tavalla. Seuraavassa ohjelmassa luokan jäseneksi määritelty kasvatusoperaattori kasvattaa jäsenmuuttujan arvoa.

255 Operaattorin toteutus on selkeä: Laskuri & Laskuri::operator++() ++arvo; return *this; Kun toteutus palauttaa this-osoittimen, voidaan sitä hyödyntää myös sijoituksessa. Seuraavana on kokonainen ohjelma, joka sisältää myös metodin Kasvata(). operator++ ohjelmassa: typedef unsigned short USHORT; class Laskuri Laskuri (); ~ Laskuri () USHORT HaeArvo()const return arvo; void AsetaArvo(USHORT x) arvo = x; void Kasvata() ++arvo; Laskuri& operator++ (); private: USHORT arvo; ; Laskuri:: Laskuri (): arvo(0) ; Laskuri & Laskuri::operator++() ++arvo; return *this; int main() Laskuri L; cout << "L:n jäsenmuuttujan arvo on " << L.HaeArvo() << endl; L.Kasvata();

256 cout << " L:n jäsenmuuttujan arvo on " << L.HaeArvo() << endl; ++L; cout << " L:n jäsenmuuttujan arvo on " << L.HaeArvo() << endl; Laskuri K = ++L; cout << " K:n jäsenmuuttujan arvo on " << K.HaeArvo() << endl; cout << " ja L:n: " << L.HaeArvo() << endl; return 0; 13.4 operator unsigned short() C++ sisältää muunnosoperaattoreita, joita voidaan lisätä luokkaan. Luokka voi määrittää, kuinka tehdä muunnokset sisäisiin tyyppeihin. Muunnosoperaattorit eivät määritä palautusarvoa, vaikka ne palauttavatkin muunnetun arvon. Seuraavassa esimerkissä unsigned short() muuntaa arvon int-tyypiksi. unsigned short() ohjelmassa: typedef unsigned short USHORT; class Laskuri Laskuri(); Laskuri(USHORT x); ~Laskuri() USHORT HaeArvo()const return arvo; void AsetaArvo(USHORT x) arvo = x; operator unsigned short(); private: USHORT arvo; ; Laskuri::Laskuri(): arvo(0) Laskuri::Laskuri(USHORT x): arvo(x) Laskuri::operator unsigned short()

257 return (int (arvo) ); int main() Laskuri L1(5); int luku = L1; cout << "Muuttujan luku arvo on: " << luku << endl; L1.AsetaArvo(10); luku = L1; cout << "Muuttujan luku arvo on nyt: " << luku << endl; return 0; 13.5 operator[] Hakasulkuoperaattorin ylimäärittely saattaa olla useinkin hyödyllinen. Voimme tällöin esimerkiksi tarkistaa, ettei taulukon rajoja ylitetä. Seuraavana on ohjelma, joka tekee indeksien tarkistuksen. operator[] ohjelmassa: #define koko 10 class taulu int indeksi; unsigned jono[koko]; taulu(unsigned arvo = 0); unsigned & operator[](int indeksi); ; taulu::taulu(unsigned arvo) for(inti=0;i<koko; i++) jono[i] = arvo; ; unsigned & taulu::operator[](int indeksi) if (indeksi <0) cout << "Indeksin on oltava positiivinen\n"; if (indeksi >= koko) cout << "Indeksi ylittää maksimikoon " << koko << "\n";

258 ; return jono[indeksi]; int main() taulu a(0); // taulukko, jossa 10 alkiota, alustetaan nollalla a[0] = 5; // Oikein! a[100] = 10;// Virheilmoitus a[-1] = 15; // Virheilmoitus return 0; 13. 6 Syötön (>>) ja tulostuksen (<<) ylimäärittely Myös syötön ja tulostuksen toteutumista voidaan muuttaa. Tulostusvirtaluokka on ostream ja syöttövirtaluokka istream. Voimme siis esitellä oliot, jotka ovat noita luokkatyyppejä ja käsitellä tulostus- ja syöttövirtoja noiden olioiden avulla. Luokat ostream ja istream on määritelty stream-kirjastossa. Seuraavana on ohjelma, jossa on tulostusoperaattori ylimääritelty. Se tulostaa muutettuna olion jäsenmuuttujan arvon. Operaattorin toteutukseen viedään parametreina tulostusolio sekä ohjelmassa määritelty olio (viittaukset niihin). Tulostuksen ylimäärittely class HLO friend ostream& operator<< (ostream& out, const HLO& hlo); HLO(int x) hlonro = x; private: int hlonro; ; ostream& operator<< (ostream& out, const HLO& hlo) return out << hlo.hlonro; main()

259 HLO Veikko(100); cout << "HLO-olio: " << Veikko << "\n"; 13.7 operator < Seuraavassa esimerkissä on operaattori < ylimääritelty vertaamaan 2 merkkijonoa keskenään: operator < #include <string.h> class String char *mj; String()mj = "KAUKO"; String( char * ); ~String() delete mj; friend int operator < (String, String); friend void main(); ; String::String(char *s) mj = new char[strlen(s) + 1]; strcpy(mj, s); int operator < (String s1, String s2) return strcmp (s1.mj, s2.mj); void main() String s0 ; String s1 ("Juhuu"); String s2 ("Heippati"); cout << s1.mj << "\n"; cout << s2.mj << "\n";

260 cout << (s1 < s0) << "\n"; cout << (s1 < s2) << "\n"; 13.8 operator() Operator() täytyy esitellä luokan jäsenenä. Sen erikoisuus on siinä, että se voidaan määritellä ottamaan useita parametreja toisin kuin muut luokan jäseninä olevat operaattorit. Seuraavana on esimerkki, jossa operator() määritellään ottamaan matriisin rivi- ja sarakemäärät parametreikseen sekä alustamaan sitten luokan tietojäsenenä olevan 2- ulotteisen taulukon. Hakasulkuoperaattoria ei voida määritellä ottamaan useampia parametreja. operator() #include <assert.h> #include <stdlib.h> const int rivit= 4; const int sarakkeet= 3; class taulu int data[rivit][sarakkeet]; int& operator() (int x, int y); friend void main(); ; int& taulu::operator() (int x, int y) assert (x >= 0 && y >= 0 && x <= rivit && y <= sarakkeet); return data[x][y]; void main() int a, b, i, j; cout << "Anna rivien määrä \n"; cin >> a; cout << "Anna sarakkeiden määrä \n"; cin >> b;

261 taulu t1; cout << "Täytetään \n"; for(i=0;i<a;i++) for(j=0;j<b;j++) t1(i,j) = rand() % 9; cout << "TULOSTETAAN \n"; for(i=0;i<a;i++) for(j=0;j<b;j++) cout << t1(i,j) << "\n";

262 Muut operaattorit operator& voidaan ylimääritellä. Vaarana on tällöin se, että osoitteeseen ei päästäkään enää ylimäärittelyn jälkeen käsiksi. &-operaattori on unaarinen (eli yksioperandinen) operaattori. Sen ylimääritteleminen on harvinaista juuri sen takia, että sitä käytetään normaalistikin luokan toiminnoissa. Pilkkuoperaattori (,) on myöskin harvoin ylimääritelty operaattori. Sitäkin käytetään normaalisti oliopohjaisissa ohjelmissa.