Ugrás a tartalomhoz

virtual

A Wikiszótárból, a nyitott szótárból

Melléknév

virtual

  1. látszólagos
  2. tulajdonképpeni

Melléknév

virtual

  1. látszólagos

Kiejtés

  • IPA: [viɾ.tu.ɐɫ]

Melléknév

virtual m or f (t.sz. virtuais)

  1. látszólagos

Kiejtés

  • IPA: /biɾˈtwal/, [biɾˈt̪wal]

Melléknév

virtual (többes szám virtuales)

  1. látszólagos

Lásd még

Főnév

virtual (tsz. virtuals)

  1. (informatika)

virtual kulcsszó C++-ban

1. Bevezetés

A virtual kulcsszó C++-ban az öröklődés egyik kulcsfontosságú eleme. Segítségével egy függvény dinamikusan kötődhet az objektumhoz, ami lehetővé teszi a polimorfizmus (többalakúság) megvalósítását.

Fő funkciója: - Lehetővé teszi, hogy az alosztályok felüldefiniálják az ősosztály függvényét. - Biztosítja, hogy a megfelelő alosztálybeli metódus fusson, amikor egy ősosztályra mutató pointeren keresztül hívunk meg egy függvényt. - Lehetővé teszi az absztrakt osztályok és a virtuális öröklődés megvalósítását.



2. virtual függvények és polimorfizmus

Ha egy függvényt virtual-ként jelölünk az ősosztályban, akkor az alosztályok felülírhatják, és a megfelelő verzió fog végrehajtódni, még akkor is, ha az ősosztályra mutató pointeren keresztül hívjuk.

Példa virtual használatára:

#include <iostream>
using namespace std;

class Szulo {
public:
    virtual void uzenet() {  // Virtuális függvény
        cout << "Szülő osztály üzenete." << endl;
    }
};

class Gyermek : public Szulo {
public:
    void uzenet() override {  // Felüldefiniálás
        cout << "Gyermek osztály üzenete." << endl;
    }
};

int main() {
    Szulo* obj = new Gyermek();
    obj->uzenet();  // A gyermek osztály függvénye hívódik meg!
    
    delete obj;
    return 0;
}

Kimenet:

Gyermek osztály üzenete.

Ha nem használnánk a virtual kulcsszót, akkor az ősosztály uzenet() függvénye hívódna meg, és nem történne meg a kívánt polimorfikus viselkedés.



3. virtual nélküli verzió

Ha az ősosztály metódusa nem virtual, akkor az ősosztály függvénye fog lefutni, még akkor is, ha az objektum egy alosztály példánya:

class Szulo {
public:
    void uzenet() {  // NEM virtuális!
        cout << "Szülő osztály üzenete." << endl;
    }
};

class Gyermek : public Szulo {
public:
    void uzenet() {  // Új függvény, nem felüldefiniálás!
        cout << "Gyermek osztály üzenete." << endl;
    }
};

int main() {
    Szulo* obj = new Gyermek();
    obj->uzenet();  // A szülő osztály metódusa hívódik meg!
    
    delete obj;
    return 0;
}

Kimenet (nem várt viselkedés!):

Szülő osztály üzenete.

Ez azért történik, mert dinamikus kötés (runtime polymorphism) csak virtual függvényekkel működik.



4. Absztrakt osztályok és pure virtual függvények

Ha egy osztály egy vagy több pure virtual függvényt tartalmaz, akkor az osztály absztrakt osztály lesz. Az absztrakt osztályból nem lehet példányt létrehozni.

class Alap {
public:
    virtual void uzenet() = 0;  // Pure virtual függvény
};

class Gyermek : public Alap {
public:
    void uzenet() override {  // Kötelező felüldefiniálni!
        cout << "Gyermek osztály üzenete." << endl;
    }
};

int main() {
    // Alap a; // HIBA! Nem lehet példányosítani, mert absztrakt osztály.
    
    Gyermek g;
    g.uzenet();  // A gyermek osztály metódusa fut le.
    
    return 0;
}

Kimenet:

Gyermek osztály üzenete.

Ha a Gyermek osztály nem definiálná felül az uzenet() függvényt, fordítási hibát kapnánk.



5. Többszörös öröklődés és virtuális öröklődés (virtual az öröklésben)

A többszörös öröklődésnél előfordulhat az ún. gyémántprobléma, amikor egy közös ősosztályt kétszer öröklünk meg.

Gyémántprobléma virtual nélkül:

class Alap {
public:
    void uzenet() {
        cout << "Alap osztály üzenete." << endl;
    }
};

class Szulo1 : public Alap {};
class Szulo2 : public Alap {};

class Gyermek : public Szulo1, public Szulo2 {};

int main() {
    Gyermek g;
    // g.uzenet();  // HIBA: Két példányban öröklődött az Alap osztály!
    return 0;
}

A megoldás a virtuális öröklés:

class Alap {
public:
    void uzenet() {
        cout << "Alap osztály üzenete." << endl;
    }
};

class Szulo1 : virtual public Alap {};
class Szulo2 : virtual public Alap {};

class Gyermek : public Szulo1, public Szulo2 {};

int main() {
    Gyermek g;
    g.uzenet();  // Nincs több példány, a probléma megoldva!
    return 0;
}

Kimenet:

Alap osztály üzenete.

6. virtual és destruktorok

Ha egy osztályt örököltetni szeretnénk, és az ősosztályban van destruktor, akkor mindig virtuálisként kell megjelölni, hogy a leszármazott osztály destruktora is lefusson:

class Szulo {
public:
    virtual ~Szulo() {  // Virtuális destruktor
        cout << "Szülő osztály destruktora." << endl;
    }
};

class Gyermek : public Szulo {
public:
    ~Gyermek() {
        cout << "Gyermek osztály destruktora." << endl;
    }
};

int main() {
    Szulo* obj = new Gyermek();
    delete obj;  // Mindkét destruktor meghívódik
    return 0;
}

Kimenet:

Gyermek osztály destruktora.
Szülő osztály destruktora.

Ha a virtual kulcsszót kihagyjuk a destruktor elől, akkor a Gyermek destruktora nem hívódna meg, ami memóriaszivárgást okozhat.



7. Összegzés

  • A virtual kulcsszó lehetővé teszi a polimorfizmus használatát.
  • Ha egy függvény virtual, akkor egy örökölt osztályban felüldefiniálható, és dinamikusan kötődik.
  • Az absztrakt osztályokat pure virtual (= 0) függvényekkel valósítjuk meg.
  • A virtuális öröklődés segít a gyémántprobléma megoldásában.
  • A destruktorokat mindig virtuálisnak kell megadni, ha egy osztályt örököltetünk.