Reihenfolge der Zerstörung mit virtuellen

8

Kann jemand bitte helfen, was die Reihenfolge der Zerstörung ist, wenn ich virtuelle Funktionen benutze. Beginnt es mit der Basisklasse und der abgeleiteten Klasse?

    
brett 17.08.2010, 21:29
quelle

8 Antworten

10

Da ich nicht sehe, wie virtuelle Funktionen die Zerstörungsreihenfolge von Objekten ändern, nehme ich an, dass Sie sich auf die Reihenfolge der Zerstörung für Basisklassen und Datenelemente in einer virtuellen Vererbung beziehen Szenario.

Unterobjekte sind konstruiert

  1. Basisklassen werden von der meisten Basis bis zu den meisten abgeleiteten ;
  2. -Konfigurationen erstellt
  3. mehrere Basisklassen werden in der Reihenfolge ihrer Deklaration als Basisklassen ;
  4. erstellt
  5. virtuelle Basisklassen werden vor allen anderen erstellt, wobei sie untereinander die obigen beiden Regeln einhalten;
  6. Datenelemente werden erstellt, bevor der Rumpf des umschließenden Objekts des Konstruktors in der Reihenfolge ihrer Deklaration ausgeführt wird.

Destruction ist einfach das Gegenteil von construction , also müssen Sie sich nur das oben genannte merken.

Aber die obigen vier Regeln sind in dieser Reihenfolge, weil das Sinn macht, und wenn Sie verstehen, warum diese Reihenfolge sinnvoll ist, werden Sie diese vier Regeln nicht einmal auswendig lernen müssen, sondern können sie aus Ihrem Verständnis ableiten (wie ich gerade tat). Sehen wir uns diese Reihenfolge an:

  • Sie können den von der Basisklasse bereitgestellten Service von einem Konstruktor einer abgeleiteten Klasse verwenden. Natürlich können Sie ein (Basis-) Klassenobjekt nicht verwenden, bevor es tatsächlich konstruiert wurde. Wenn eine abgeleitete Klasse erstellt wird, muss daher die Basisklasse bereits konstruiert sein. (Übrigens erklärt dies auch, warum die virtuelle Funktionszuteilung in Konstruktoren nicht vollständig funktioniert: Wenn ein Unterobjekt konstruiert wird, werden nur die Unterobjekte von Basisklassen konstruiert, die Unterobjekte der abgeleiteten Klassen noch nicht Daher darf ein Aufruf einer virtuellen Funktion nicht an eine abgeleitete Klasse gesendet werden. Wie immer sind Destruktoren gleich, nur rückwärts.)
  • Da mehrere Basisklassen zu gleichen Geschwistern gehören, musste eine bestimmte Reihenfolge willkürlich ausgewählt werden. Letztlich ist die Reihenfolge der Deklaration am einfachsten zu verwenden. Datenelemente, die ebenfalls gleichwertige Geschwister sind, folgen derselben (mehr oder weniger willkürlichen) In-der-Deklarationsregel.
  • Virtuelle Basisklassen sind seltsame Bestien. Da es immer nur ein Unterobjekt einer virtuellen Basisklasse geben wird, gibt es diese spezielle Regel, die besagt, dass sie immer zuerst konstruiert werden muss, direkt vom Konstruktor der abgeleiteten Klasse. (Aus diesem Grund funktionieren virtuelle Basisklassen am besten als abstrakte Basisklassen ohne Daten und nur als Standardkonstruktoren.)
sbi 17.08.2010, 21:43
quelle
4

Angenommen, Sie haben Ihren Destruktor korrekt als virtuell deklariert.

Dann erfolgt die Zerstörung in genau umgekehrter Reihenfolge der Konstruktion.

Im Allgemeinen wird dies sein:

A) Beginnen Sie in der abgeleiteten Klasse.
B) Wiederhole das Folgende rekursiv.

1) Führen Sie den Destruktorcode aus.
2) Führe den Destruktor jedes Mitglieds (in umgekehrter Reihenfolge der Erstellung) aus 3) Führen Sie den Destruktor der Elternklasse aus. (wenn mehr als eins in umgekehrter Reihenfolge der Erstellung)

Wenn Sie die virtuelle Vererbung verwenden, dann sind die Dinge etwas anders, da die Reihenfolge der Basisklassenkonstruktionen nicht mit der normalen übereinstimmt. ABER Die Reihenfolge der Zerstörung ist IMMER das Gegenteil der Reihenfolge der Konstruktion.

    
Martin York 17.08.2010 21:31
quelle
1

Die Zerstörungsreihenfolge ist die Konstruktionsreihenfolge rückwärts. Ich habe kürzlich ein kleines Tool erstellt, um die Konstruktionsreihenfolge für jede Hierarchie anzuzeigen. Schau hier:

In den Diagrammen werden die Knoten mit den kleineren Zahlen zuerst und zuletzt zerstört.

    
Nordic Mainframe 17.08.2010 21:32
quelle
1

Abschnitt 12.6.2 / 5:

  

Die Initialisierung wird in der folgenden Reihenfolge durchgeführt:

     
  • Zuerst und nur für den Konstruktor der abgeleiteten Klasse as   Wie unten beschrieben, sollen virtuelle Basisklassen in der   Reihenfolge erscheinen sie auf einer Tiefe-zuerst von links nach rechts Durchquerung der   gerichtetes azyklisches Diagramm der Basisklassen, wobei "von links nach rechts" das ist   Reihenfolge des Auftretens der Basisklassennamen in der abgeleiteten Klasse   Base-Specifier-Liste.
  •   
  • Dann sollen direkte Basisklassen initialisiert werden   in der Deklarationsreihenfolge, wie sie in der Basisspezifiziererliste erscheinen   (unabhängig von der Reihenfolge der Mem-Initialisierer).
  •   
  • Dann, nicht statisch   Datenelemente werden in der Reihenfolge initialisiert, in der sie deklariert wurden   die Klassendefinition (wiederum unabhängig von der Reihenfolge der   mem-Initialisierer). - Schließlich wird der Rumpf des Konstruktors ausgeführt.
  •   

[Hinweis: Die Deklarationsreihenfolge ist vorgeschrieben, um sicherzustellen, dass die Basis und die   Teilobjekte werden in umgekehrter Reihenfolge zerstört   Initialisierung. ]

    
Chubsdad 18.08.2010 09:19
quelle
0

Es ist der umgekehrte Weg wie die Konstrukteure. Also zuerst abgeleitet.

    
schoetbi 17.08.2010 21:31
quelle
0

Reihenfolge der Zerstörungen, wenn von unten nach oben. (von abgeleiteten zur Basis)

  

Kurze Antwort: das genaue Gegenteil von   die Konstruktorreihenfolge.

     

Lange Antwort: Angenommen, die meisten   abgeleitet "Klasse ist D, was bedeutet   tatsächliches Objekt, das ursprünglich war   erstellt wurde von Klasse D, und das D   erbt multipliziert (und nicht virtuell)   von B1 und B2. Das Unterobjekt   entspricht der am meisten abgeleiteten Klasse D   läuft zuerst, gefolgt von den dtors für   seine nicht virtuellen Basisklassen in   umgekehrte Deklarationsreihenfolge Und so kam es dass der   Destruktorreihenfolge ist D, B2, B1.   Diese Regel wird rekursiv angewendet. zum   Beispiel, wenn B1 von B1a und   B1b und B2 erbt von B2a und B2b,   die letzte Reihenfolge ist D, B2, B2b, B2a,   B1, B1b, B1a.

Siehe c ++ faq-Abschnitt 25

    
Tom 17.08.2010 21:32
quelle
0

Virtuelle Funktionen machen keinen Unterschied in der Reihenfolge der Zerstörung, virtuelle Basisklassen andererseits.

Ohne virtuelle Basisklassen werden abgeleitete Klassen immer vor ihren Basisklassen zerstört; Dies ist die umgekehrte Reihenfolge, in der sie konstruiert sind.

Für die am weitesten abgeleitete Klasse werden virtuelle Basisklassen zuerst vor anderen Basisklassen und vor der am weitesten abgeleiteten Klasse selbst erstellt. Die Zerstörung geschieht in umgekehrter Reihenfolge. Dies bedeutet, dass eine virtuelle Basis nach einer Klasse, die virtuell von ihr abgeleitet ist, zerstört werden kann, wenn diese Klasse nicht die am weitesten abgeleitete Klasse ist, die zerstört wird. Dies kann niemals für direkte Basisklassen passieren.

    
Charles Bailey 17.08.2010 21:31
quelle
0

Zuerst die abgeleitete, dann die Basis. Kein Unterschied zu den nicht-virtuellen Fällen.

Zusätzliche Anmerkung. Wenn Sie Vererbungs- und virtuelle Methoden verwenden, müssen Sie Destruktoren als virtuell deklarieren, andernfalls können Sie beim Löschen undefiniertes Verhalten haben.

Beispiel: Angenommen, Derived wird von Base abgeleitet, und Sie ordnen Derived mit der folgenden Zeile zu:

%Vor%

Wenn dieser Fall in Ihrem Code auftritt und Base keinen virtuellen Destruktor hat, ist das resultierende Verhalten nicht definiert. Normalerweise wird nur der Destruktor von Base aufgerufen. Der Destruktor von Derived wird nicht aufgerufen, da Sie delete für einen Basiszeiger aufrufen. Das Programm stürzt jedoch möglicherweise ab. Sobald Sie sich im Bereich des undefinierten Verhaltens befinden, sind alle Wetten deaktiviert und Ihr Ausführungscode ist zum Scheitern verurteilt. Um Chaos zu vermeiden, muss der Base-Destruktor virtuell sein.

    
Stefano Borini 17.08.2010 21:33
quelle