Programozás II. 9. gyakorlat Operátor overloading 2: Unáris operátorok, globálisan megvalósított operátorok, << és >> operátorok Kivételkezelés, IO library
Globális operátor overloading Előző alkalommal megnéztük, hogy lehet kétoperandusú operátort felüldefiniálni Ekkor a bal oldali operandus volt az objektum, amire meghívtuk az operátort, a jobb oldali operandust kapja paraméterben Fordítva ez lehetséges?
Globális operátor overloading Pl. az összeadás a valóságban felcserélhető művelet Nálunk is? - Nem Tort t1(1, 2); int a = 3; Tort t2 = t1 + a; //ez működhet Tort t3 = a + t1; //ez nem működik Ez azért van, mert a bal oldali operandus típusára (int) nem létezik operátor, aminek a jobb oldali operandusa Tort
Globális operátor overloading A megoldás az, hogy definiáljuk a másik operandusra is ezt az operátort Ez sokszor nem lehetséges: Bal oldali operandus primitív típus (ld. előbb) Bal oldali osztályhoz nem férünk hozzá (<< felüldefiniálása, ld. Később) Megoldás a globálisan megvalósított operátor overloading
Globális operátor overloading Ekkor az operátort nem az osztály metódusaként, hanem egy külső függvényként definiáljuk Két paramétere lesz, a két operandus Nincs hozzá this pointer A többi része megegyezik az előző esettel Mi a helyzet a privát láthatóságú adattagokkal?
Friend függvények Ha egy metódust friend láthatósággal látunk el, akkor az látni fogja az osztály adattagjait (private-et és protectedet is), de globális függvény lesz Így tetszőleges sorrendben lehetnek az operandusok Szintaxis: class Tort { friend Tort& operator+(int, Tort&); };
Unáris operátorok (++ és --) Beépített típusoknál ismerős a ++ és -- operátor Volt prefix és postfix alakja is Prefix alaknál értelmezhető a múltkori szabály: Az első (egyetlen) operandus saját maga Nincs másik operandus, így paramétere nincs Tort& operator++() { this->m_dszamlalo += this->m_dnevezo; return *this; }
Unáris operátorok (++ és --) A postfix operátort viszont hogy jelöljük? A globális megvalósítás nem megoldás, mert továbbra is csak egy paraméter van Megoldás: adjunk a metódusnak egy int paramétert (amit később nem használunk semmire) Tort& operator++(int) { Tort* old = new Tort(*this); this->m_dszamlalo += this->m_dnevezo; return *old; }
IO stream operátorok << és >> Segítségével a saját osztályainkat is egyszerűen behelyezhetjük bármilyen streambe kb. mint Javaban a tostring() Ez csak globálisan valósítható meg, mert a baloldali operandus mindig a stream Mindig visszatért a streamre mutató referenciával (amibe betettük), hogy láncolható legyen a kifejezés Fontos: implementáláskor mindig a kapott streambe helyezzük az objektumunkat, és ne coutra (vagy egyéb helyre)
Kivételkezelés Alapelve ugyan az, mint Javaban A kivételkezelés lehetővé teszi, hogy reagáljunk a program futása során felmerülő kivételes eseményekre úgy, hogy a vezérlést egy speciálisan erre készített programrésznek (kezelőnek). (Forrás) Szintaxisa is hasonló
Kivételkezelés Kivételt dobni a throw utasítással tudunk Dobhatunk int, char*, saját osztályt vagy kivételosztályt try kulcsszóval jelölhetjük az un. kritikus blokkot, ahol figyeljük a kivételeket catch kulcsszóval jelöljük a kezelő (handler) blokkot ( ) mindent elkap Létrehozhatunk saját kivételosztályt, ha származtatjuk az exception ősosztályból Felüldefiniálhatjuk a what() metódust
IO stream library Két ősosztály: ios_base és ios Típusfüggetlen metódusok streamek számára Ezeknek két leszármazottja az istream és ostream Ennek a kettőnek a leszármazottja pedig az iostream Ennek a példányai a cout, cin és cerr Családfa
Hasznos referenciák IO-hoz istream, ostream fstream, ifstream, ofstream operator<<, operator>>
Hátralévő teendők Következő héten ismétlés, gyakorlás Két hét múlva 2. kötprog (kiírások coospacen) 3-4 hét múlva gyakorlati ZH