Ich habe ein solides Verständnis der meisten OO-Theorie, aber die eine Sache, die mich sehr verwirrt, sind virtuelle Destruktoren.
Ich dachte, dass der Destruktor immer aufgerufen wird, egal was und für jedes Objekt in der Kette.
Wann sollte man sie virtuell machen und warum?
Virtuelle Destruktoren sind nützlich, wenn Sie möglicherweise eine Instanz einer abgeleiteten Klasse durch einen Zeiger auf die Basisklasse löschen können:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
Hier werden Sie feststellen, dass ich den Destruktor von Base nicht als "virtuell" deklariert habe. Werfen wir nun einen Blick auf das folgende Snippet:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Da der Destruktor von Base nicht virtuell
ist und b
eine Base*
ist, die auf ein Derived
Objekt zeigt, hat delete b
undefiniertes Verhalten:
[In
delete b
], wenn der statische Typ des zu löschenden Objekts von seinem dynamischen Typ abweicht, muss der statische Typ eine Basisklasse des dynamischen Typs des zu löschenden Objekts sein zu löschenden Objekts sein und der statische Typ muss einen virtuellen Destruktor haben oder das Verhalten ist undefiniert.
In den meisten Implementierungen wird der Aufruf des Destruktors wie jeder nicht-virtuelle Code aufgelöst, was bedeutet, dass der Destruktor der Basisklasse aufgerufen wird, nicht aber der der abgeleiteten Klasse, was zu einem Ressourcenleck führt.
Zusammenfassend lässt sich sagen, dass die Destruktoren von Basisklassen immer virtuell
sein sollten, wenn sie polymorph manipuliert werden sollen.
Wenn Sie das Löschen einer Instanz durch einen Basisklassenzeiger verhindern wollen, können Sie den Destruktor der Basisklasse geschützt und nicht-virtuell machen; auf diese Weise lässt der Compiler nicht zu, dass Sie delete
auf einen Basisklassenzeiger aufrufen.
Sie können mehr über Virtualität und virtuelle Basisklassenzerstörer in diesem Artikel von Herb Sutter erfahren.
Deklarieren Sie Destruktoren in polymorphen Basisklassen als virtuell. Dies ist Punkt 7 in Scott Meyers' Effective C++. Meyers fasst zusammen, dass eine Klasse, die irgendeine virtuelle Funktion hat, einen virtuellen Destruktor haben sollte, und dass Klassen, die nicht als Basisklassen oder zur polymorphen Verwendung vorgesehen sind, keine virtuellen Destruktoren deklarieren sollten.
Machen Sie den Destruktor virtuell, wenn Ihre Klasse polymorph ist.