Wenn eine Klasse virtuelle Methoden enthält, sollte sie zusätzlich auch den Destruktor virtuell beschreiben.
Nehmen wir folgendes Szenario an:
#include <stdio.h> #include <stdlib.h> class Node { public: Node * Next; Node * Prev; char * UserData; Node() : Next( NULL ) , Prev( NULL ) { UserData = new char[500]; } ~Node() { printf( "Destruiere Node - loesche UserData\n" ); delete [] UserData; } }; class MyNode : public Node { public: char * MoreData; MyNode() { MoreData = new char[500]; } ~MyNode() { printf( "Destruiere MyNode - loesche MoreData\n" ); delete [] MoreData; } }; void deleteNode( Node * toDelete ) { delete toDelete; } int main( void ) { MyNode *myNode1, *myNode2; myNode1 = new MyNode; myNode2 = new MyNode; deleteNode( myNode1 ); delete( myNode2 ); return EXIT_SUCCESS; }
Dieses Programm ist nicht objektorientiert, die Funktion deleteNode
erhält einen Pointer auf Node
und gibt diesen frei. Da der Destruktor nicht virtuell ist, also nicht Objekttyp-Abhängig ist, ruft C++ den Destruktor entsprechend des Datentypes von toDelete
- und das ist Node, nicht MyNode.
Schauen wir uns die Ausgaben an:
Destruiere Node - loesche UserData Destruiere MyNode - loesche MoreData Destruiere Node - loesche UserData
Obwohl die Funktion deleteNode einen Zeiger auf ein Objekt der Klasse MyNode
erhält, geht Information, dass es sich um ein MyNode handelt verloren und C++ sieht in deleteNode
nur noch den Zeiger auf ein Node
und ruft den Konstruktor, der für Node
gilt. Da der Destruktor nicht virtual ist, wird Node::~Node() gerufen. Dies ist aber ja nicht gewünscht, zuerst muss ja der Destruktor MyNode::~MyNode gerufen werden, damit auch der Member MoreData
freigegeben wird und dieser Destruktor anschließend den Destruktor seiner Basisklasse ruft.
Um das einzurichten, erklären wir den Destruktor von Node
für virtual:
virtual ~Node() { printf( "Destruiere Node - loesche UserData\n" ); delete [] UserData; }
Nun weiß delete, dass es den Destruktor in der virtual Table suchen muss und findet dort den Destruktor von ~MyNode
.
Somit erhalten wir das richtige Ergebnis:
Destruiere MyNode - loesche MoreData Destruiere Node - loesche UserData Destruiere MyNode - loesche MoreData Destruiere Node - loesche UserData