Konstruktoren und Destruktoren sind spezielle Elementfunktionen. Im Allgemeinen wird überall gelesen, dass die Konstruktion vom am wenigsten abgeleiteten Typ beginnt und sich hierarchisch bis zum am meisten abgeleiteten Typ fortsetzt. Dies ist tatsächlich die Reihenfolge, in der die Konstruktor-Ausführung abgeschlossen wird, aber nicht, wie die Konstruktion gestartet wird.
Die Ausführungsreihenfolge der Konstruktor-Initialisierungsliste garantiert, dass während der am meisten abgeleitete Objekt-Konstruktor der erste Konstruktor ist, der mit der Ausführung beginnt, wird er der letzte Konstruktor sein, der abgeschlossen wird.
Wenn Sie ein Objekt instanziieren, wird zuerst der am meisten abgeleitete Konstruktor aufgerufen, der dem Konstruktionsaufruf entspricht. Die Initialisierungsliste des übereinstimmenden am meisten abgeleiteten Konstruktors beginnt, und Initialisierungslisten haben eine feste Reihenfolge: zuerst werden die Konstruktoren der Basisklassen in der Reihenfolge des Auftretens innerhalb der Vererbungsliste aufgerufen. Dann werden die Konstruktoren der Member-Attribute in der Reihenfolge aufgerufen, in der sie in der Klassendeklaration erscheinen (nicht in der Reihenfolge, in der sie in der Initialisierungsliste erscheinen). Nachdem die gesamte Initialisierungsliste (auf jeder Ebene) abgeschlossen ist, wird der Konstruktorblock ausgeführt, nachdem der Konstruktionsaufruf abgeschlossen ist.
Alle Basiskonstruktoren werden in umgekehrter Reihenfolge der Konstruktion aufgerufen, nachdem der am meisten abgeleitete Destruktor die Ausführung abgeschlossen hat. Die Zerstörung erfolgt in genau umgekehrter Reihenfolge der Konstruktion.
Destruktoren sind auf eine andere Weise speziell: sie können nicht überschrieben werden. Wenn Sie den am meisten abgeleiteten Destruktor einer Klasse aufrufen, wird die Ausführung des Destruktionsblocks abgeschlossen, nachdem alle Member-Objektdestruktoren in umgekehrter Reihenfolge der Erstellung aufgerufen wurden. Nachdem der am meisten abgeleitete Destruktor abgeschlossen ist und auch die Member-Destruktoren des am meisten abgeleiteten Objekts abgeschlossen sind, beginnen die Destruktoren seiner direktesten Basen in umgekehrter Reihenfolge der Konstruktion, die Destruktorblocks werden ausgeführt, dann die Member-Attribute-Destruktoren und so weiter... Am Ende werden alle erstellten Elemente zerstört.
Destruktoren für polymorphe Klassen sollten virtuell sein
Die oben beschriebene Zerstörung beginnt mit dem Aufruf des am meisten abgeleiteten Destruktors. Dies kann erreicht werden, indem Sie delete
auf einen Zeiger auf den am meisten abgeleiteten Typ aufrufen, wenn ein automatisches Objekt den Gültigkeitsbereich verlässt oder wenn das Objekt über eine Basisklasse, deren Destruktor virtuell ist, gelöscht wird.
Wenn Sie vergessen, das Destruktor-Keyword in der Basisklasse hinzuzufügen und versuchen, ein abgeleitetes Objekt über einen Zeiger auf die Basis zu löschen, rufen Sie direkt den Basendestruktor auf, und das impliziert, dass alle Unterelemente unterhalb des Zeigertyps in der Hierarchie nicht ordnungsgemäß zerstört werden. Alle Vererbungshierarchien, in denen Objekte über Zeiger auf einen Basistyp gelöscht werden, müssen virtuelle Destruktoren haben. Als Faustregel gilt, wenn Sie bereits eine virtuelle Methode haben, ist der Aufwand, den Destruktor virtuell zu machen, vernachlässigbar und eine sichere Lösung. Viele Kodierungsrichtlinien fordern, dass Destruktoren in Vererbungshierarchien virtuell sein müssen. Einige gehen so weit zu verlangen, dass alle Destruktoren virtuell sind. Dies hat den Zweck, mögliche Ressourcenlecks zu vermeiden, jedoch mit dem Nachteil, dass für alle Typen eine vtable und für alle Objekte ein vtable-Zeiger hinzugefügt werden müssen.