A C++ programozási nyelvSoós Sándor 1/12 C++ programozási nyelv Gyakorlat - 8. hét Nyugat-Magyarországi Egyetem Faipari Mérnöki Kar Informatikai Intézet Soós Sándor november
A C++ programozási nyelvSoós Sándor 2/12 Tartalomjegyzék ● Miért örököltetünk osztályokat? ● 1. példa ● A virtual kulcsszó ● 2. példa ● Polimorfizmus, többalakúság ● Early binding, late binding ● Binding példa ● Miért jó a polimorfizmus? ● Pure virtual, tisztán virtuális metódusok ● Mire jók az absztrakt osztályok?
A C++ programozási nyelvSoós Sándor 3/12 Miért örököltetünk osztályokat? ● 1. eset: – Gyerek = szülő + valami ● a gyerek mindent tud, amit a szülő + tud még mást is ● ezzel az esettel foglalkoztunk a múlt héten ● 2. eset – Gyerek = szülő, másképp ● a gyerek ugyanazokat a dolgokat tudja, mint a szülő, de másképp ● ezzel foglalkozunk ma! ● A gyakorlatban a két dolog együtt zajlik. ● Általában egy gyerek egyrészt kiterjeszti a szülőjét újabb funkciókkal, másrészt egyes örökölt tulajdonságokat (metódusokat) módosít (felüldefiniál).
A C++ programozási nyelvSoós Sándor 4/12 1. példa class Szemely { public: virtual void Koszon(); }; void Szemely::Koszon() { printf("Jó napot!\n"); }; class Diak : public Szemely { public: virtual void Koszon(); }; void Diak::Koszon() { printf("Jó szerencsét!\n"); }; class Diak : public Szemely { public: virtual void Koszon(); }; void Diak::Koszon() { printf("Jó szerencsét!\n"); }; int main() { Szemely sz; Diak d; sz.Koszon();// Jó napot! d.Koszon();// Jó szerencsét! return 0; }; Ebben az esetben nem történt semmi váratlan. Ha most elhagynám a virtual kulcsszót, ugyanez lenne az eredmény. Ebben az esetben nem történt semmi váratlan. Ha most elhagynám a virtual kulcsszót, ugyanez lenne az eredmény.
A C++ programozási nyelvSoós Sándor 5/12 A virtual kulcsszó ● Két helyen írtuk le a virtual kulcsszót: – a szülőben – a gyerekben ● Mindkét helyen csak a deklarációban, a definícióban nem szabad kiírni! ● Ha most elhagynám, akkor ez a példa változatlanul működne, de nem célszerű elhagyni! ● Amikor egy függvényt felül fogunk definiálni az utódokban, akkor használjuk a virtual-t a szülő osztályban! – Erre később még visszatérünk! ● A gyerek osztályban mindegy, hogy kiírjuk-e, de érdemes kiírni dokumentációs szempontból, a program működését nem befolyásolja.
A C++ programozási nyelvSoós Sándor 6/12 2. példa ● A leszármazott egy felüldefiniált metódusban meghívhatja az ősének ugyanilyen nevű metódusát ● Mi történik, ha a Diak::Koszon-ben kihagyom a Szemely:: -t? ● Ezt is leírhatom a main-ben: d.Szemely::Koszon(); – szintaktikailag helyes, de kerülendő! Az objektum belső dolgait ne használjuk fel kívül. void Diak::Koszon() { Szemely::Koszon(); printf("Jó szerencsét!\n"); }; int main() { Diak d; d.Koszon();// Jó napot! // Jó szerencsét! return 0; };
A C++ programozási nyelvSoós Sándor 7/12 Polimorfizmus, többalakúság ● Nézzük meg a pelda3.cpp fájlt! ● Mi történik, ha nem virtualnak deklarálom a Koszon függvényt? ● Vizsgáljuk meg az f1() – f4() függvényeket!
A C++ programozási nyelvSoós Sándor 8/12 Egy kis háttér: Early binding, late binding ● Mit befolyásol a virtual kulcsszó? ● Amikor a fordító találkozik egy metódus meghívásával, akkor kétféleképpen járhat el: – ha a metódus nem virtuális, akkor a hívás helyére beírja az ott szereplő osztály hívott metódusának kezdőcímét, illetve az annak megfelelő jelzést. Ez fordítási időben megtörténik (early binding – korai kötés) – ha a metódus virtuális, akkor fordításkor csak egy hivatkozás kerül ide az osztályhoz tartozó Virtuális Metódus Tábla (VMT) megfelelő bejegyzésére – A VMT futás időben kerül kitöltésre, csak ekkor dől el, hogy az egyes virtuális metódusok ténylegesen milyen memóriacímre mutatnak (late binding – késői kötés) ● Nézzük meg az előző példa f1() függvényét!
A C++ programozási nyelvSoós Sándor 9/12 Binding példa void f1( Szemely &sz) { printf("f1: "); sz.Koszon(); }; ● Ha a Koszon() metódus nem virtuális, akkor az f1() lefordításakor sz.Koszon() helyére a Szemely osztály Koszon metódusának címe kerül. ● Ha viszont Koszon() virtuális, akkor ide csak az a jelzés kerül, hogy az f1()-nek átadott paraméter VMT táblájának 1. helyén szereplő címre kell ugrani. Majd futás időben derül, ki, hogy az f1() függvénynek milyen típusú objektumot adtunk át. ● A polimorfizmus miatt ez valóban csak futásidőben derül ki.
A C++ programozási nyelvSoós Sándor 10/12 Miért jó a polimorfizmus? ● Nézzük meg a Jegypenztar.cpp fájlt! – Egy programozó megírta a Jegypenztar() függvényt. – Később bármikor létrehozhatunk egy újabb leszármazottat a Szemelyből, arra is működni fog a Jegypenztar, még csak újra sem kell fordítani. ● Konténerben kezelt objektumok (geometria hf) – Ha egy konténerben (például egy tömbben) szeretnénk tárolni különböző típusú objektumokat (például a síkidomokat), akkor a közös ősből hozzuk létre a konténert. (Tömb esetén csak pointerekkel működik mindez!) – Ezek után egy ciklusban sorra lefuttathatjuk például a Kirajzoló, virtuális metódust. Minden síkidom esetén a megfelelő metódus fog lefutni.
A C++ programozási nyelvSoós Sándor 11/12 Pure virtual, tisztán virtuális metódusok class Szemely { public: virtual void Koszon() = 0; }; ● Ezzel a szintaktikával jelöljük a tisztán virtuális metódusokat. ● Absztrakt osztály: – van legalább egy tisztán virtuális tagfüggvénye – nem példányosítható ● Nézzük meg az absztrakt.cpp fájlt!
A C++ programozási nyelvSoós Sándor 12/12 Mire jók az absztrakt osztályok? ● Nyelvi eszközökkel segítik a tervezést. ● Az absztrakt osztályban deklaráljuk, hogy milyen metódusokat kell mindenképpen megvalósítani egy osztályban ahhoz, hogy példányosítani lehessen azt. ● Amíg nem írtuk meg az összes pure virtual metódust, addig nem lehet példányt létrehozni belőle. ● Miért fontos ez? – ez azt jelenti, hogy ezekre a tulajdonságokra (metódusokra) biztosan számíthatunk minden leszármazott osztályban ● Tervezzük tovább a múlt órai geometriai oktatóprogramot az új fogalmak felhasználásával!