Virtuálna funkcia (známa aj ako virtuálne metódy) je členská funkcia, ktorá je deklarovaná v rámci základnej triedy a je predefinovaná (prepísaná) odvodenou triedou. Keď odkazujete na objekt odvodenej triedy pomocou ukazovateľa alebo odkazu na základnú triedu, môžete pre tento objekt zavolať virtuálnu funkciu a spustiť verziu metódy odvodenej triedy.
palindróm v Jave
- Virtuálne funkcie zabezpečujú, že sa pre objekt zavolá správna funkcia, bez ohľadu na typ odkazu (alebo ukazovateľa) použitého na volanie funkcie.
- Používajú sa hlavne na dosiahnutie Runtime polymorfizmu.
- Funkcie sú deklarované s a virtuálne kľúčové slovo v základnej triede.
- Vyriešenie volania funkcie sa vykonáva za behu.
Pravidlá pre virtuálne funkcie
Pravidlá pre virtuálne funkcie v C++ sú nasledovné:
- Virtuálne funkcie nemôžu byť statické.
- Virtuálna funkcia môže byť funkcia priateľa inej triedy.
- Virtuálne funkcie by mali byť prístupné pomocou ukazovateľa alebo referencie typu základnej triedy, aby sa dosiahol polymorfizmus za behu.
- Prototyp virtuálnych funkcií by mal byť rovnaký v základnej aj odvodenej triede.
- Vždy sú definované v základnej triede a prepísané v odvodenej triede. Pre odvodenú triedu nie je povinné prepísať (alebo predefinovať virtuálnu funkciu), v takom prípade sa použije verzia základnej triedy funkcie.
- Trieda môže mať virtuálny deštruktor, ale nemôže mať virtuálny konštruktor.
Čas kompilácie (skoré viazanie) správanie virtuálnych funkcií VS runtime (neskoré viazanie).
Uvažujme o nasledujúcom jednoduchom programe, ktorý ukazuje správanie virtuálnych funkcií za behu.
C++
// C++ program to illustrate> // concept of Virtual Functions> #include> using> namespace> std;> class> base {> public>:> >virtual> void> print() { cout <<>'print base class
'>; }> >void> show() { cout <<>'show base class
'>; }> };> class> derived :>public> base {> public>:> >void> print() { cout <<>'print derived class
'>; }> >void> show() { cout <<>'show derived class
'>; }> };> int> main()> {> >base* bptr;> >derived d;> >bptr = &d;> >// Virtual function, binded at runtime> >bptr->print();> >// Non-virtual function, binded at compile time> >bptr->show();> >return> 0;> }> |
>
algoritmy triedenia vkladania
>Výkon
print derived class show base class>
Vysvetlenie: Polymorfizmus za behu sa dosiahne iba prostredníctvom ukazovateľa (alebo odkazu) typu základnej triedy. Ukazovateľ základnej triedy môže tiež ukazovať na objekty základnej triedy, ako aj na objekty odvodenej triedy. Vo vyššie uvedenom kóde obsahuje ukazovateľ základnej triedy „bptr“ adresu objektu „d“ odvodenej triedy.
Neskorá väzba (Runtime) sa vykonáva v súlade s obsahom ukazovateľa (t. j. umiestnenie, na ktoré ukazuje ukazovateľ) a skorá väzba (čas kompilácie) sa vykonáva podľa typu ukazovateľa, pretože funkcia print() je deklarovaná pomocou virtuálneho kľúčové slovo, takže bude viazané za behu (výstup je trieda odvodená od tlače keďže ukazovateľ ukazuje na objekt odvodenej triedy) a show() je nevirtuálna, takže bude viazaná počas kompilácie (výstup je zobraziť základnú triedu keďže ukazovateľ je základného typu).
jednoduchý program python
Poznámka: Ak sme vytvorili virtuálnu funkciu v základnej triede a je prepísaná v odvodenej triede, potom v odvodenej triede nepotrebujeme virtuálne kľúčové slovo, funkcie sa automaticky považujú za virtuálne funkcie v odvodenej triede.
Práca s virtuálnymi funkciami (koncept VTABLE a VPTR)
Ako je uvedené tu, ak trieda obsahuje virtuálnu funkciu, potom samotný kompilátor robí dve veci.
- Ak sa vytvorí objekt tejto triedy, potom a virtuálny ukazovateľ (VPTR) sa vloží ako údajový člen triedy, aby ukázal na VTABLE tejto triedy. Pre každý nový vytvorený objekt sa vloží nový virtuálny ukazovateľ ako dátový člen danej triedy.
- Bez ohľadu na to, či je objekt vytvorený alebo nie, trieda obsahuje ako člena statické pole ukazovateľov funkcií s názvom VTABLE . Bunky tejto tabuľky ukladajú adresu každej virtuálnej funkcie obsiahnutej v danej triede.
Zvážte príklad nižšie:

ako previesť z reťazca na int
C++
pripojenie k databáze v jazyku Java
// C++ program to illustrate> // working of Virtual Functions> #include> using> namespace> std;> class> base {> public>:> >void> fun_1() { cout <<>'base-1
'>; }> >virtual> void> fun_2() { cout <<>'base-2
'>; }> >virtual> void> fun_3() { cout <<>'base-3
'>; }> >virtual> void> fun_4() { cout <<>'base-4
'>; }> };> class> derived :>public> base {> public>:> >void> fun_1() { cout <<>'derived-1
'>; }> >void> fun_2() { cout <<>'derived-2
'>; }> >void> fun_4(>int> x) { cout <<>'derived-4
'>; }> };> int> main()> {> >base* p;> >derived obj1;> >p = &obj1;> >// Early binding because fun1() is non-virtual> >// in base> >p->fun_1();> >// Late binding (RTP)> >p->fun_2();> >// Late binding (RTP)> >p->fun_3();> >// Late binding (RTP)> >p->fun_4();> >// Early binding but this function call is> >// illegal (produces error) because pointer> >// is of base type and function is of> >// derived class> >// p->fun_4(5);> >return> 0;> }> |
>
>Výkon
base-1 derived-2 base-3 base-4>
Vysvetlenie: Na začiatok vytvoríme ukazovateľ typu základná trieda a inicializujeme ho adresou objektu odvodenej triedy. Keď vytvoríme objekt odvodenej triedy, kompilátor vytvorí ukazovateľ ako dátový člen triedy obsahujúci adresu VTABLE odvodenej triedy.
Podobný koncept Neskorá a skorá väzba sa používa ako vo vyššie uvedenom príklade. Pre volanie funkcie fun_1() sa volá verzia základnej triedy funkcie, fun_2() je prepísaná v odvodenej triede, takže sa volá verzia odvodenej triedy, fun_3() nie je prepísaná v odvodenej triede a ide o virtuálnu funkciu takže sa volá verzia základnej triedy, podobne fun_4() nie je prepísaná, takže sa volá verzia základnej triedy.
Poznámka: fun_4(int) v odvodenej triede sa líši od virtuálnej funkcie fun_4() v základnej triede, pretože prototypy oboch funkcií sú odlišné.
Obmedzenia virtuálnych funkcií
- Pomalšie: Volanie funkcie trvá o niečo dlhšie kvôli virtuálnemu mechanizmu a kompilátoru sťažuje optimalizáciu, pretože presne nevie, ktorá funkcia sa bude volať v čase kompilácie. Ťažko laditeľné: V zložitom systéme môžu virtuálne funkcie trochu sťažiť zistenie, odkiaľ sa funkcia volá.