Miskolci Egyetem Általános Informatikai Tanszák
Virtuális függvények (late binding) Ficsor Lajos Miskolci Egyetem Általános Informatikai Tanszék Ficsor Lajos
Virtuális függvények
CPP5 /
1
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 Ficsor Lajos
Virtuális függvények
CPP5 /
2
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";} }; Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
3
CPP4/ 1
Miskolci Egyetem Általános Informatikai Tanszák
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";} }; Ficsor Lajos
Virtuális függvények
CPP5 /
4
CPP5 /
5
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 Ficsor Lajos
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
Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
6
CPP4/ 2
Miskolci Egyetem Általános Informatikai Tanszák
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 Ficsor Lajos
Virtuális függvények
CPP5 /
7
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óprogram azonosí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 Ficsor Lajos
Virtuális függvények
CPP5 /
8
Virtuális függvény: formai szabályok • Csak tagfüggvény definiálható virtuálisnak, az osztálydeklaráció törzsében elhelyezett virtual alapszó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. Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
9
CPP4/ 3
Miskolci Egyetem Általános Informatikai Tanszák
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). Ficsor Lajos
Virtuális függvények
CPP5 /
10
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. Ficsor Lajos
Virtuális függvények
CPP5 /
11
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ő
Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
12
CPP4/ 4
Miskolci Egyetem Általános Informatikai Tanszák
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. Ficsor Lajos
Virtuális függvények
CPP5 /
13
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";} }; Ficsor Lajos
Virtuális függvények
CPP5 /
14
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";} }; Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
15
CPP4/ 5
Miskolci Egyetem Általános Informatikai Tanszák
CPPEX14.C (folytatás) main () { 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 gepkocsi kerekeinek szama: 4 Ficsor Lajos
Virtuális függvények
CPP5 /
16
CPP5 /
17
Példa: grafikus elemek, 1. verzió Location
X : Integer Y : Integer GetX() : Integer GetY() : Integer
Point Visible : Boolean Show() Hide() MoveTo(NewX : Integer, NewY : Integer) IsVisible() : Boolean
Circle Radius : Integer Hide() Show() MoveTo(NewX : Integer, NewY : Integer) Expand(Ratio : Single)
Square
Ellipse
Radius1 : Integer Hide() Show() Show() MoveTo(NewX : Integer, NewY : Integer) Hide() Ficsor Virtuális függvények Expand(Ratio : Single) MoveTo(NewX : Integer, NewY : Integer) Lajos
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 }; Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
18
CPP4/ 6
Miskolci Egyetem Általános Informatikai Tanszák
Példa: grafikus elemek 1. verz. 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)! Ficsor Lajos
Virtuális függvények
CPP5 /
19
CPP5 /
20
Példa: grafikus elemek 2. verzió Location X : Integer Y : Integer GetX() : Integer GetY() : Integer
Point Visible : Boolean
<
> Show() <> Hide() MoveTo(NewX : Integer, NewY : Integer) IsVisible() : Boolean
Circle Radius : Integer Hide() Show() Expand(Ratio : Single)
Ellipse
Square
Ficsor Lajos
Radius1 : Integer
Hide() Show() Virtuális függvények Expand(Ratio : Single)
Show() Hide()
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 Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
21
CPP4/ 7
Miskolci Egyetem Általános Informatikai Tanszák
Példa a haszná használatra const int MAXELEM=100; Location* elemek[MAXELEM]; int aktElemszam=0; // Uj rajzelem letrehozasa aktElemszam++; elemek[aktElemszam] = new ……
Ficsor Lajos
Virtuális függvények
CPP5 /
22
Példa a haszná használatra (folyt.) // Osszes elem ujra rajzolasa for (int i=0; i Show();
Ficsor Lajos
Ficsor Lajos
Virtuális függvények
CPP5 /
23
CPP4/ 8