En virtuel funktion (også kendt som virtuelle metoder) er en medlemsfunktion, der er erklæret inden for en basisklasse og omdefineres (tilsidesættes) af en afledt klasse. Når du henviser til et afledt klasseobjekt ved hjælp af en pointer eller en reference til basisklassen, kan du kalde en virtuel funktion for det objekt og udføre den afledte klasses version af metoden.
eksempel binært søgetræ
- Virtuelle funktioner sikrer, at den korrekte funktion kaldes for et objekt, uanset hvilken type reference (eller pointer), der bruges til funktionskaldet.
- De bruges hovedsageligt til at opnå Runtime polymorfisme.
- Funktioner erklæres med en virtuelle nøgleord i en basisklasse.
- Løsningen af et funktionskald udføres under kørsel.
Regler for virtuelle funktioner
Reglerne for de virtuelle funktioner i C++ er som følger:
- Virtuelle funktioner kan ikke være statiske.
- En virtuel funktion kan være en vennefunktion af en anden klasse.
- Virtuelle funktioner bør tilgås ved hjælp af en pointer eller reference af basisklassetype for at opnå runtime polymorfi.
- Prototypen af virtuelle funktioner skal være den samme i basen såvel som den afledte klasse.
- De er altid defineret i basisklassen og tilsidesat i en afledt klasse. Det er ikke obligatorisk for den afledte klasse at tilsidesætte (eller omdefinere den virtuelle funktion), i så fald bruges basisklasseversionen af funktionen.
- En klasse kan have en virtuel destruktor, men den kan ikke have en virtuel konstruktør.
Kompileringstid (tidlig binding) VS runtime (sen binding) adfærd for virtuelle funktioner
Overvej følgende enkle program, der viser køretidsadfærden for virtuelle funktioner.
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->vis();> >return> 0;> }> |
>
>Produktion
print derived class show base class>
Forklaring: Runtime polymorfi opnås kun gennem en pointer (eller reference) af basisklassetypen. En basisklassepointer kan også pege på objekterne i basisklassen såvel som til objekterne i den afledte klasse. I ovenstående kode indeholder basisklassemarkøren 'bptr' adressen på objektet 'd' for den afledte klasse.
Sen binding (Runtime) udføres i overensstemmelse med indholdet af pointeren (dvs. placering, der peges på af pointeren), og tidlig binding (Compile-time) udføres i henhold til typen af pointer, da print()-funktionen er deklareret med den virtuelle søgeord, så det vil være bundet under kørsel (output er trykafledt klasse da markøren peger på objekt af afledt klasse) og show() er ikke-virtuel, så den vil være bundet under kompileringstiden (output er vis basisklasse da markøren er af basistype).
Bemærk: Hvis vi har oprettet en virtuel funktion i basisklassen, og den bliver tilsidesat i den afledte klasse, behøver vi ikke et virtuelt nøgleord i den afledte klasse, funktioner betragtes automatisk som virtuelle funktioner i den afledte klasse.
Betjening af virtuelle funktioner (konceptet VTABLE og VPTR)
Som diskuteret her, hvis en klasse indeholder en virtuel funktion, så gør compileren selv to ting.
- Hvis et objekt af den klasse er oprettet, så a virtuel pointer (VPTR) er indsat som et datamedlem af klassen for at pege på VTABLE for den pågældende klasse. For hvert nyt objekt, der oprettes, indsættes en ny virtuel pointer som et datamedlem af den pågældende klasse.
- Uanset om objektet er oprettet eller ej, indeholder klassen som et medlem en statisk række af funktionspointere kaldet VTABLE . Celler i denne tabel gemmer adressen på hver virtuelle funktion indeholdt i den pågældende klasse.
Overvej eksemplet nedenfor:

C++
java åbner en fil
// 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->sjov_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;> }> |
>
>Produktion
base-1 derived-2 base-3 base-4>
Forklaring: Indledningsvis opretter vi en pointer af typen basisklasse og initialiserer den med adressen på det afledte klasseobjekt. Når vi opretter et objekt af den afledte klasse, opretter compileren en pointer som et datamedlem af klassen, der indeholder adressen på VTABLE for den afledte klasse.
Et lignende koncept af Sen og tidlig indbinding bruges som i ovenstående eksempel. For fun_1() funktionskaldet kaldes basisklasseversionen af funktionen, fun_2() tilsidesættes i den afledte klasse, så den afledte klasseversion kaldes, fun_3() tilsidesættes ikke i den afledte klasse og er en virtuel funktion så basisklasseversionen kaldes, ligesom fun_4() ikke tilsidesættes, så basisklasseversionen kaldes.
Bemærk: fun_4(int) i den afledte klasse er forskellig fra den virtuelle funktion fun_4() i basisklassen, da prototyper af begge funktioner er forskellige.
Begrænsninger af virtuelle funktioner
- Langsommere: Funktionskaldet tager lidt længere tid på grund af den virtuelle mekanisme og gør det sværere for compileren at optimere, fordi den ikke ved præcis, hvilken funktion der skal kaldes på kompileringstidspunktet. Svært at fejlfinde: I et komplekst system kan virtuelle funktioner gøre det lidt sværere at finde ud af, hvor en funktion kaldes fra.