polymorphism |
---|
ad hoc polymorphism |
parametric polymorphism |
subtyping |
dynamic dispatch (tsz. dynamic dispatches)
Base*
vagy Base&
típusú változót használunk.
#include <iostream>
class Base {
public:
virtual void print() { // Virtuális függvény
std::cout << "Base osztály print()" << std::endl;
}
};
class Derived : public Base {
public:
void print() override { // Felülírja a virtuális függvényt
std::cout << "Derived osztály print()" << std::endl;
}
};
int main() {
Base* obj = new Derived(); // Dinamikus allokáció
obj->print(); // Futási időben dől el, hogy a Derived::print() hívódik meg
delete obj;
return 0;
}
Derived osztály print()
Mi történik itt? - Az obj
egy Base* típusú pointer, de valójában egy Derived
objektumot mutat. - Az obj->print()
híváskor a program nem a Base verzióját hívja, hanem a Derived::print()
metódust. - Ez azért lehetséges, mert a print()
függvény virtuális, és így dinamikus diszpécselést használ.
A dinamikus diszpécselés a virtuális táblát (VTable) és a virtuális pointert (VPTR) használja.
Ha egy osztályban van pure virtual function, az osztály absztrakt osztály lesz, és nem példányosítható.
#include <iostream>
class Shape {
public:
virtual void draw() = 0; // Pure virtual function (kötelező felülírni)
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Kör kirajzolása" << std::endl;
}
};
int main() {
// Shape obj; // Ez NEM működik, mert Shape absztrakt osztály!
Shape* s = new Circle();
s->draw(); // Futási időben a Circle::draw() hívódik meg
delete s;
return 0;
}
Kör kirajzolása
Mi történik itt? - A Shape
osztályban a draw()
pure virtual function (= 0
). - A Shape
absztrakt osztály, tehát nem példányosítható. - A Circle
osztály felülírja a draw()
függvényt. - A s->draw();
hívás a Circle::draw()
függvényt hívja meg dinamikusan.
Ha egy osztályt dinamikusan öröklődő polimorf objektumokként használunk, a destruktorának virtuálisnak kell lennie, különben memóriaszivárgás léphet fel.
#include <iostream>
class Base {
public:
~Base() { std::cout << "Base destruktor" << std::endl; }
};
class Derived : public Base {
public:
~Derived() { std::cout << "Derived destruktor" << std::endl; }
};
int main() {
Base* obj = new Derived();
delete obj; // Csak a Base destruktora hívódik meg! (Derived destruktora NEM!)
return 0;
}
Base destruktor
A Derived
destruktora NEM fut le, ami memóriaszivárgást okozhat.
#include <iostream>
class Base {
public:
virtual ~Base() { std::cout << "Base destruktor" << std::endl; }
};
class Derived : public Base {
public:
~Derived() { std::cout << "Derived destruktor" << std::endl; }
};
int main() {
Base* obj = new Derived();
delete obj; // Most mindkét destruktor meghívódik
return 0;
}
Derived destruktor Base destruktor
Megjegyzés: Ha egy osztály rendelkezik virtuális függvényekkel, akkor a destruktorát is mindig virtuálisnak kell megadni!
virtual
) biztosítják a dinamikus kötést.= 0
) absztrakt osztályokat hoz létre.virtual ~Destructor()
) megakadályozza a memóriaszivárgást.Ha polimorfikus osztályokat használsz, mindig gondoskodj a helyes destruktorok beállításáról, hogy elkerüld a memória problémákat! 🚀