15 Stimmen

Wird der Konstruktor und Destruktor einer Basisklasse mit den abgeleiteten aufgerufen?

Ich habe eine Klasse namens MyBase, die einen Konstruktor und Destruktor hat:

class MyBase
{
public:
    MyBase(void);
    ~MyBase(void);
};

und Ich habe eine Klasse namens Banana, die MyBase erweitert, wie folgt:

class Banana:public MyBase
{
public:
    Banana(void);
    ~Banana(void);
};

Wird die Implementierung des neuen Konstruktors und Destruktors in Banana die MyBase überschreiben, oder existieren sie noch und werden vor oder nach dem Banana-Konstruktor / Destruktor aufgerufen?

Danke und entschuldigen Sie, wenn meine Frage albern erscheint.

18voto

Arkaitz Jimenez Punkte 21364

Ein Basiskonstruktor wird immer vor dem abgeleiteten Konstruktor aufgerufen. Der Basiskonstruktor wird nach dem abgeleiteten Destruktor aufgerufen.

Sie können im abgeleiteten Konstruktor angeben, welchen Basiskonstruktor Sie möchten, andernfalls wird der Standardwert ausgeführt.

Wenn Sie andere Konstruktoren definieren, aber keinen Standardwert angeben und im abgeleiteten Konstruktor nicht angeben, welcher ausgeführt werden soll, wird der Standardwert versucht, der nicht existiert und die Kompilierung abstürzt.

Das oben Genannte geschieht, weil sobald Sie einen Konstruktor deklarieren, keine Standardkonstruktoren generiert werden.

9voto

mmx Punkte 400975

Konstruktoren können nicht überschrieben werden. Sie können einen Basisklassenkonstruktor nicht in einer abgeleiteten Klasse deklarieren. Ein Klassenkonstruktor muss vor irgendetwas anderem einen Konstruktor in der Basisklasse aufrufen (wenn keiner explizit angegeben ist, wird der Standardkonstruktor aufgerufen).

Um die abgeleitete Klasse ordnungsgemäß bereinigen zu können, sollte der Basisklassen-Destruktor als virtual deklariert werden:

virtual ~MyBase() { ... }

7voto

György Andrasek Punkte 7947

Es sollte sagen

class Banane : public MeinBasis
{
public:
    Banane(void);
    ~Banane(void);
};

Der Konstruktor der abgeleiteten Klasse wird nach dem Konstruktor der Basisklasse aufgerufen. Die Destruktoren werden in umgekehrter Reihenfolge aufgerufen.

4voto

Mark Ransom Punkte 283960

Die Konstruktoren werden von oben nach unten im Vererbungsbaum aufgerufen. So kann der abgeleitete Konstruktor darauf vertrauen, dass das Basenobjekt vollständig initialisiert ist, bevor es versucht, Eigenschaften des Basen zu verwenden.

Destruktoren werden in umgekehrter Reihenfolge der Konstruktoren aufgerufen, aus dem gleichen Grund - die abgeleiteten Klassen sind abhängig vom Basen, aber das Basen ist nicht abhängig von den Abgeleiteten.

Wenn es irgendeine Möglichkeit gibt, das Objekt über einen Zeiger auf eine Basisklasse zu zerstören, müssen Sie alle Destruktoren als virtual deklarieren.

4voto

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X