logo

Virtuaalifunktio C++:ssa

Virtuaalinen funktio (tunnetaan myös nimellä virtuaalimenetelmät) on jäsenfunktio, joka on ilmoitettu perusluokassa ja jonka johdettu luokka määrittelee (korvaa) uudelleen. Kun viittaat johdettuun luokkaobjektiin osoittimella tai viittauksella perusluokkaan, voit kutsua kyseisen objektin virtuaalisen funktion ja suorittaa johdetun luokan menetelmän version.

vaihda väri gimpissä
  • Virtuaalifunktiot varmistavat, että objektille kutsutaan oikeaa funktiota riippumatta funktiokutsussa käytetyn viittauksen (tai osoittimen) tyypistä.
  • Niitä käytetään pääasiassa ajonaikaisen polymorfismin saavuttamiseen.
  • Funktiot ilmoitetaan a:lla virtuaalinen avainsana perusluokassa.
  • Funktion kutsun ratkaiseminen tehdään suorituksen aikana.

Virtuaalitoimintojen säännöt

Virtuaalifunktioiden säännöt C++:ssa ovat seuraavat:

  1. Virtuaalifunktiot eivät voi olla staattisia.
  2. Virtuaalinen funktio voi olla toisen luokan ystäväfunktio.
  3. Virtuaalifunktioita tulee käyttää perusluokkatyypin osoittimen tai viittauksen avulla ajonaikaisen polymorfismin saavuttamiseksi.
  4. Virtuaalifunktioiden prototyypin tulee olla sama sekä perusluokassa että johdetussa luokassa.
  5. Ne määritellään aina perusluokassa ja ohitetaan johdetussa luokassa. Johdetun luokan ei ole pakollista ohittaa (tai määrittää uudelleen virtuaalifunktiota), siinä tapauksessa käytetään funktion perusluokan versiota.
  6. Luokassa voi olla virtuaalinen tuhoaja, mutta sillä ei voi olla virtuaalista rakentajaa.

Virtuaalisten funktioiden käännösaika (varhainen sidonta) VS ajonaikainen (myöhäinen sidonta) käyttäytyminen

Harkitse seuraavaa yksinkertaista ohjelmaa, joka näyttää virtuaalisten toimintojen ajonaikaisen käyttäytymisen.



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->tulosta();> >// Non-virtual function, binded at compile time> >bptr->näytä();> >return> 0;> }>

>

>

Lähtö

print derived class show base class>

Selitys: Ajonaikainen polymorfismi saavutetaan vain perusluokkatyypin osoittimen (tai viitteen) avulla. Myös perusluokan osoitin voi osoittaa perusluokan objekteihin sekä johdetun luokan objekteihin. Yllä olevassa koodissa perusluokan osoitin 'bptr' sisältää johdetun luokan objektin 'd' osoitteen.

Myöhäinen sidonta (Runtime) tehdään osoittimen sisällön (eli osoittimen osoittaman sijainnin) mukaisesti ja varhainen sidonta (käännösaika) tehdään osoittimen tyypin mukaan, koska print()-funktio on ilmoitettu virtuaalisen funktion kanssa. avainsana, joten se sidotaan suorituksen aikana (tulostus on tulosta johdettu luokka koska osoitin osoittaa johdetun luokan objektiin) ja show() on ei-virtuaalinen, joten se sidotaan käännösaikana (tulos on näytä perusluokka koska osoitin on perustyyppiä).

Huomautus: Jos olemme luoneet virtuaalisen funktion perusluokassa ja se ohitetaan johdetussa luokassa, emme tarvitse virtuaalista avainsanaa johdettuun luokassa, vaan funktiot katsotaan automaattisesti virtuaalifunktioiksi johdetussa luokassa.

Virtuaalitoimintojen toiminta (käsite VTABLE ja VPTR)

Kuten tässä on käsitelty, jos luokka sisältää virtuaalisen funktion, kääntäjä itse tekee kaksi asiaa.

  1. Jos tuon luokan objekti luodaan, niin a virtuaalinen osoitin (VPTR) lisätään luokan datajäseneksi osoittamaan kyseisen luokan VTABLE:hen. Jokaiselle luodulle uudelle objektille lisätään uusi virtuaalinen osoitin kyseisen luokan tietojäseneksi.
  2. Riippumatta siitä, onko objekti luotu vai ei, luokka sisältää jäsenenä staattinen joukko funktioosoittimia nimeltä VTABLE . Tämän taulukon solut tallentavat kunkin luokan virtuaalifunktion osoitteen.

Harkitse alla olevaa esimerkkiä:

virtuaalinen osoitin ja virtuaalipöytä

monirivinen kommentti powershell

C++




// 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->hauska_1();> >// Late binding (RTP)> >p->hauska_2();> >// Late binding (RTP)> >p->hauska_3();> >// Late binding (RTP)> >p->hauska_4();> >// Early binding but this function call is> >// illegal (produces error) because pointer> >// is of base type and function is of> >// derived class> >// p->hauska_4(5);> >return> 0;> }>

>

>

Lähtö

base-1 derived-2 base-3 base-4>

Selitys: Aluksi luomme perusluokka-tyypin osoittimen ja alustamme sen johdetun luokkaobjektin osoitteella. Kun luomme johdetun luokan objektin, kääntäjä luo osoittimen luokan tietojäseneksi, joka sisältää johdetun luokan VTABLE-osoitteen.

Samanlainen käsite Myöhäinen ja varhainen sidonta käytetään kuten yllä olevassa esimerkissä. Fun_1()-funktiokutsussa kutsutaan funktion perusluokan versiota, fun_2() ohitetaan johdetussa luokassa, joten johdettua luokkaversiota kutsutaan, fun_3() ei ohiteta johdetussa luokassa ja on virtuaalinen funktio. joten perusluokan versiota kutsutaan, samoin fun_4() ei ohiteta, joten perusluokan versiota kutsutaan.

instant java

Huomautus: fun_4(int) johdetussa luokassa eroaa perusluokan virtuaalifunktiosta fun_4(), koska molempien funktioiden prototyypit ovat erilaisia.

Virtuaalitoimintojen rajoitukset

    Hitaampi: Funktiokutsu kestää hieman kauemmin virtuaalimekanismin vuoksi ja vaikeuttaa kääntäjän optimointia, koska se ei tiedä tarkalleen mitä funktiota kutsutaan käännöshetkellä. Vaikea virheenkorjaus: Monimutkaisessa järjestelmässä virtuaalifunktiot voivat vaikeuttaa hieman funktiota kutsuvan paikan selvittämistä.