O funcție virtuală (cunoscută și ca metode virtuale) este o funcție membru care este declarată într-o clasă de bază și este redefinită (supracrisă) de o clasă derivată. Când vă referiți la un obiect de clasă derivată folosind un pointer sau o referință la clasa de bază, puteți apela o funcție virtuală pentru acel obiect și puteți executa versiunea clasei derivate a metodei.
boolean la șir java
- Funcțiile virtuale asigură apelarea funcției corecte pentru un obiect, indiferent de tipul de referință (sau pointer) utilizat pentru apelul funcției.
- Ele sunt utilizate în principal pentru a realiza polimorfismul Runtime.
- Funcțiile sunt declarate cu a virtual cuvânt cheie într-o clasă de bază.
- Rezolvarea unui apel de funcție se face în timpul execuției.
Reguli pentru funcțiile virtuale
Regulile pentru funcțiile virtuale din C++ sunt următoarele:
- Funcțiile virtuale nu pot fi statice.
- O funcție virtuală poate fi o funcție prietenă a unei alte clase.
- Funcțiile virtuale ar trebui să fie accesate folosind un pointer sau o referință de tipul clasei de bază pentru a obține polimorfismul de rulare.
- Prototipul funcțiilor virtuale ar trebui să fie același în clasa de bază, precum și în clasa derivată.
- Ele sunt întotdeauna definite în clasa de bază și suprascrise într-o clasă derivată. Nu este obligatoriu ca clasa derivată să suprascrie (sau să redefinească funcția virtuală), în acest caz, se utilizează versiunea clasei de bază a funcției.
- O clasă poate avea un destructor virtual, dar nu poate avea un constructor virtual.
Comportamentul timpului de compilare (legare timpurie) VS timpul de execuție (legare tardivă) al funcțiilor virtuale
Luați în considerare următorul program simplu care arată comportamentul de rulare al funcțiilor virtuale.
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->arată();> >return> 0;> }> |
>
lista de state
>
metode javaIeșire
print derived class show base class>
Explicaţie: Polimorfismul runtime este realizat doar printr-un pointer (sau referință) de tipul clasei de bază. De asemenea, un pointer de clasă de bază poate indica obiectele clasei de bază, precum și obiectele clasei derivate. În codul de mai sus, indicatorul clasei de bază „bptr” conține adresa obiectului „d” al clasei derivate.
Legarea tardivă (Runtime) se face în conformitate cu conținutul pointerului (adică locația indicată de pointer) și legarea timpurie (timpul de compilare) se face în funcție de tipul de pointer, deoarece funcția print() este declarată cu virtualul cuvânt cheie, astfel încât acesta va fi legat în timpul rulării (ieșirea este clasa derivată tipar deoarece pointerul indică obiectul clasei derivate) și show() nu este virtual, așa că va fi legat în timpul compilării (ieșirea este arată clasa de bază întrucât indicatorul este de tip bază).
Notă: Dacă am creat o funcție virtuală în clasa de bază și este suprascrisă în clasa derivată, atunci nu avem nevoie de un cuvânt cheie virtual în clasa derivată, funcțiile sunt considerate automat funcții virtuale în clasa derivată.
Funcționarea funcțiilor virtuale (conceptul de VTABLE și VPTR)
După cum am discutat aici, dacă o clasă conține o funcție virtuală, atunci compilatorul însuși face două lucruri.
- Dacă este creat un obiect din acea clasă, atunci a pointer virtual (VPTR) este inserat ca membru de date al clasei pentru a indica VTABLE a acelei clase. Pentru fiecare obiect nou creat, un nou pointer virtual este inserat ca membru de date al acelei clase.
- Indiferent dacă obiectul este creat sau nu, clasa conține ca membru o matrice statică de indicatori de funcție numită VTABLE . Celulele acestui tabel stochează adresa fiecărei funcții virtuale conținute în acea clasă.
Luați în considerare exemplul de mai jos:

java și swing
C++
instrucțiunea javascript if
// 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;> }> |
>
>Ieșire
base-1 derived-2 base-3 base-4>
Explicaţie: Inițial, creăm un pointer de tipul clasă de bază și îl inițializam cu adresa obiectului clasei derivate. Când creăm un obiect al clasei derivate, compilatorul creează un pointer ca membru de date al clasei care conține adresa VTABLE a clasei derivate.
Un concept similar de Legare tardivă și timpurie este folosit ca în exemplul de mai sus. Pentru apelul funcției fun_1(), se apelează versiunea clasei de bază a funcției, fun_2() este suprascrisă în clasa derivată, astfel încât versiunea clasei derivate este numită, fun_3() nu este suprascrisă în clasa derivată și este o funcție virtuală deci versiunea clasei de bază este numită, în mod similar fun_4() nu este suprascris, așa că versiunea clasei de bază este apelată.
Notă: fun_4(int) din clasa derivată este diferită de funcția virtuală fun_4() din clasa de bază, deoarece prototipurile ambelor funcții sunt diferite.
Limitări ale funcțiilor virtuale
- Mai lent: apelul funcției durează puțin mai mult din cauza mecanismului virtual și îngreunează optimizarea compilatorului, deoarece nu știe exact ce funcție va fi apelată în timpul compilării. Dificil de depanat: într-un sistem complex, funcțiile virtuale pot face un pic mai dificil de a afla de unde este apelată o funcție.