2016-04-25 6 views
2

Ich habe diese Situation:Welchen Typ für eine virtuelle Funktion hat eine Klasse, wenn ein Member-Destruktor ausgeführt wird?

#include <iostream> 

struct B { virtual void f() { std::cout << "base"; } }; 

struct A { 
    ~A() { 
     b->f(); 
    } 

    B *b; 
}; 


struct Bd : B { 
    Bd():a{this}{ } 
    ~Bd() { } 
    virtual void f() { std::cout << "derived"; } 

    A a; 
}; 

int main() { 
    Bd d; 
} 

Ist sichergestellt, dass dieser Druck "abgeleitet"?

+1

Ich denke, es wird entweder 'B :: f 'aufrufen oder undefiniertes Verhalten aufrufen. Die Lebensdauer eines Objekts endet formal [wenn Destruktoren beginnen] (http://en.cppreference.com/w/cpp/language/lifetime), also wenn 'A :: ~ A' 'b-> f() aufruft ; ',' b's abgeleiteter Teil ist bereits tot. – Quentin

+0

werfen Sie auch einen Blick auf [diese] (http://stackoverflow.com/questions/12092933/calling-virtual-function-from-destructor) – sp2danny

+0

@Quentin dieses Zitat sieht überhaupt nicht gut aus. Sie können definitiv auf ein Objekt von seinem eigenen Destruktor zugreifen, was im Widerspruch zu dem Verbot steht, auf das Objekt zuzugreifen, sobald seine Lebensdauer endet. –

Antwort

2

[class.cdtor]/4:

Member-Funktionen, einschließlich virtueller Funktionen ([class.virtual]), kann während des Baus oder der Zerstörung ([class.base.init]) aufgerufen werden. Wenn ist eine virtuelle Funktion, die direkt oder indirekt von einem Konstruktor oder von einem Destruktor bezeichnet, während des Baus oder der Zerstörung einschließlich des nicht-statische Datenelemente der Klasse, und dem Objekt, auf das die Anruf gilt, ist das Objekt (Nennen Sie es x) im Bau oder Zerstörung, die aufgerufene Funktion ist der letzte Overrider in der Klasse des Konstruktors oder Destruktors und nicht in einer Klasse mehr abgeleitete Klasse.

„Die Klasse“ hier in Rede ist Bd, so dass es die endgültige Übergehungseinrichtung von f() in Bd nennen soll, und druckt derived.

0

Ich habe keine Zeit, um es jetzt zu suchen, aber die Regel ist, dass ein virtueller Aufruf für ein Objekt, dessen Destruktor ausgeführt wird, an die Klasse geht, deren Destruktor gerade ausgeführt wird. So im Destruktor für Bd läuft der Destruktor für a, und der Aufruf b->f() ruft Bd::f.

Wenn a Mitglied B gewesen statt Bd, würde der Aufruf von B::f gehen, weil der Destruktor von a von B ‚s destructor laufen würde.

Wenn Sie es vorziehen, an Mechanismen zu denken (im Allgemeinen nicht), denken Sie an die vtable; Beim Eintragen in einen Destruktor setzt der Code den Zeiger auf die vtable des Destruktors, der gerade ausgeführt wird.

Verwandte Themen