230 likes | 354 Views
Virtuális függvények (late binding). Ficsor Lajos Miskolci Egyetem Általános Informatikai Tanszék. Azonos nevű függvények megkülönböztetése. paraméterszignatúra (függvény overloading) - egy hatáskörön belül SCOPE operátor segítségével (classname::fname)
E N D
Virtuális függvények(late binding) Ficsor Lajos Miskolci Egyetem Általános Informatikai Tanszék Virtuális függvények
Azonos nevű függvények megkülönböztetése • paraméterszignatúra (függvény overloading) - egy hatáskörön belül • SCOPE operátor segítségével (classname::fname) • mezőkiválasztó operátor (objname.fname) Ez a megkülönböztetés fordítási időben megtörténik. Származtatás: gond lehet az azonos nevű függvényekkel. Megoldás:late binding (késői kötés) Nyelvi eszköz:virtuális függvény Virtuális függvények
CPPEX12.C class jarmu { protected: int kerekek; double suly; public: jarmu (int k, double s) {kerekek = k; suly = s;} void hanykerek (void) { cout << "A jarmu kerekeinek szama: " << kerekek << "\n";} }; Virtuális függvények
CPPEX12.C (folyt.) class gepkocsi : public jarmu { protected: int szemelyek; public: gepkocsi (int k, double s, int szem) : jarmu (k, s) { szemelyek = szem; } void hanykerek (void) { cout << "A gepkocsi kerekeinek szama: " << kerekek << "\n";} }; Virtuális függvények
CPPEX12.C (folyt.) main () { jarmu bicikli (2,15); bicikli.hanykerek(); gepkocsi trabant (4, 120.0, 4); trabant.hanykerek(); } // Az eremeny: // A jarmu kerekeinek szama: 2 // A gepkocsi kerekeinek szama: 4 Virtuális függvények
CPPEX12.C - tanulságok A tagfüggvény meghívása objektumhoz kapcsolva • az objektum osztálya határozza meg a hatáskört, amelyben a függvény definíciót keresni kell • a fordítóprogram azonosítani tudja a függvényt • a megfelelő függvény hívódik meg Virtuális függvények
CPPEX13.C main ()// A CPPEX12 osztalydefiniciojaval { jarmu *kerekes; kerekes = new jarmu (2,15.); kerekes->hanykerek(); kerekes = new gepkocsi (4, 120.0, 4); kerekes->hanykerek(); } // Az eredmeny: // A jarmu kerekeinek szama: 2 // A jarmu kerekeinek szama: 4 Virtuális függvények
CPPEX13.C - tanulságok A tagfüggvény meghívása objektumra mutató pointer segítségével • a pointer alaptípusa határozza meg az osztályt, amelynek hatáskörében a függvény definíciót keresni kell • a fordítóprogramazonosítani tudja a függvényt • nem a megfelelő függvény hívódik meg, ha a pointer alaptípusa és az általa megcímzett objektum típusa eltér Virtuális függvények
Virtuális függvény: formai szabályok • Csak tagfüggvény definiálható virtuálisnak, az osztálydeklaráció törzsében elhelyezett virtualalapszóval. • Az öröklődési hierarchiában lejjebb álló osztályok tartalmazhatnak ugyanilyen nevű, paraméter szignatúrájú és visszatérési értékű tagfügvényeket. • Ezek a függvények a virtual alapszó nélkül is virtuálisnak minősülnek. Virtuális függvények
Formai szabályok (folyt.) • A virtuális függvényt a bázisosztályban köteleződefiniálni, a leszármazottak mindegyikében nem. • A bázisosztályban a virtuális függvény lehet valódi virtuális függvény - ekkor 0-val kell inicializálni. Például: virtual void hanykerek () = 0; • Az ilyen osztály nem példányosítható (absztrakt osztály). Virtuális függvények
Formai szabályok (folyt.) • Ha mutatón keresztül hívjuk meg a virtuális függvényt, nem a mutató alaptípusa határozza meg, hogy melyik változatot kell használni, hanem a megcímzett objektum típusa. • A megcímzett objektum típusa általában csak futási időben derül ki • A fordítóprogram általában nem tudja megkeresni a meghívandó függvényt, csak előkészíteni a futásidejű kiválasztását. Virtuális függvények
Virtuális függvény használata Használata: • ugyanolyan funkciók a leszármazott osztályokban • a funkció implementációja osztályfüggő Virtuális függvények
Virtuális függvény korai kötéssel Az alábbi esetekben a virtuális függvény hívását is fel tudja dolgozni a fordítóprogram fordítási időben (korai kötés): • Objektum hivatkozáson keresztül hívjuk meg. • SCOPE operátorral explicite meghatározzuk a definíció helyét. • A bázisosztály konstruktorában vagy destruktorában hívjuk meg. Virtuális függvények
CPPEX14.C class jarmu { protected: int kerekek; double suly; public: jarmu (int k, double s) {kerekek = k; suly = s;} virtual void hanykerek (void) { cout << "A jarmu kerekeinek szama: " << kerekek << "\n";} }; Virtuális függvények
CPPEX14.C (folytatás) class gepkocsi : public jarmu { protected: int szemelyek; public: gepkocsi (int k, double s, int szem) : jarmu (k, s) { szemelyek = szem; } void hanykerek (void) { cout << "A gepkocsi kerekeinek szama: " << kerekek << "\n";} }; Virtuális függvények
CPPEX14.C (folytatás) main () { jarmu *kerekes; kerekes = new jarmu (2,15.); kerekes->hanykerek(); delete kerekes; // Ha precizek akarunk // lenni kerekes = new gepkocsi (4, 120.0, 4); kerekes->hanykerek(); } // Az eredmeny: // A jarmu kerekeinek szama: 2 // A gepkocsi kerekeinek szama: 4 Virtuális függvények
Példa: grafikus elemek, 1. verzió Virtuális függvények
Példa: grafikus elemek 1. verzió (folyt.) Implementációk: void Point::MoveTo(int NewX, int NewY) { Hide(); // aktuális törlése X = NewX; // új pozíció Y = NewY; Show(); // megjelenítés az új helyen }; void Circle::MoveTo(int NewX, int NewY) { Hide(); // aktuális törlése X = NewX; // új pozíció Y = NewY; Show(); // megjelenítés az új helyen }; Virtuális függvények
Példa: grafikus elemek 1. verz. (folyt.) A két implementáció azonosnak tűnik, mert azonos az algoritmus. A különbség: • a Point::MoveTo-ban a Point::Hide() hívódik meg • a Circle::MoveTo-ban a Circle::Hide() hívódik meg Ezért nem örökölhető a MoveTo (azaz külön implementáció szükséges minden osztályra)! Virtuális függvények
Példa: grafikus elemek 2. verzió Location X : Integer Y : Integer GetX() : Integer GetY() : Integer Point Visible : Boolean <<virtual>>Show() <<virtual>> Hide() MoveTo(NewX : Integer, NewY : Integer) IsVisible() : Boolean Circle Radius : Integer Hide() Show() Expand(Ratio : Single) Ellipse Square Radius1 : Integer Hide() Virtuális függvények Show() Show() Hide() Expand(Ratio : Single)
Példa: grafikus elemek 2. verzió (folyt.) Különbségek: • a Show és Hide függvények virtuálisak • a MoveTo függvény öröklődik Eredmény: • a MoveTo függvény a this->Showés this->Hide függvényeket hívja meg • a this mutató által megcímzett objektum típusa (amellyel a MoveTo-t használtuk) dönt • az objektum aktuális típusa csak futásidőben dől el Virtuális függvények
Példa a használatra const int MAXELEM=100; Location* elemek[MAXELEM]; int aktElemszam=0; // Uj rajzelem letrehozasa aktElemszam++; elemek[aktElemszam] = new …… Virtuális függvények
Példa a használatra (folyt.) // Osszes elem ujra rajzolasa for (int i=0; i<aktElemszam; i++) elemek[i] -> Show(); Virtuális függvények