2009-03-24 9 views
267

Beim Überschreiben einer Klasse in C++ (mit einem virtuellen Destruktor) implementiere ich den Destruktor wieder als virtuell in der erbenden Klasse, aber muss ich den Base Destruktor aufrufen?Muss ich den virtuellen Destruktor der Basis explizit aufrufen?

Wenn so stelle ich mir etwas so ...

MyChildClass::~MyChildClass() // virtual in header 
{ 
    // Call to base destructor... 
    this->MyBaseClass::~MyBaseClass(); 

    // Some destructing specific to MyChildClass 
} 

Habe ich Recht?

Antwort

365

Nein, Destruktoren werden automatisch in umgekehrter Reihenfolge der Konstruktion aufgerufen. (Basisklassen dauern). Rufen Sie keine Basisklassen-Destruktoren auf.

+0

Was ist mit reinen virtuellen Destruktoren? Mein Linker versucht, ihn am Ende des nicht-virtuellen Destruktors meiner geerbten Klasse aufzurufen. – cjcurrie

+32

Sie können keinen reinen virtuellen Destruktor ohne einen Körper haben. Gib ihm einfach einen leeren Körper. Bei einer regulären rein virtuellen Methode wird stattdessen die Overriding-Funktion aufgerufen, bei Destruktoren werden sie alle aufgerufen, so dass Sie einen Body bereitstellen müssen. Das = 0 bedeutet nur, dass es überschrieben werden muss, also immer noch ein nützliches Konstrukt, wenn Sie es brauchen. –

+1

Diese Frage könnte verwandt sein und Hilfe [Fragen/15265106/c-a-missing-vtable-Fehler] (http://stackoverflow.com/questions/15265106/c-a-missing-vtable-error). –

80

Nein, Sie müssen den Basisdestruktor nicht aufrufen, ein Basisdestruktor wird immer von dem abgeleiteten Destruktor für Sie aufgerufen. Please see my related answer here for order of destruction.

Um zu verstehen, warum Sie einen virtuellen Destruktor in der Basisklasse möchten, finden Sie den Code unten:

class B 
{ 
public: 
    virtual ~B() 
    { 
     cout<<"B destructor"<<endl; 
    } 
}; 


class D : public B 
{ 
public: 
    virtual ~D() 
    { 
     cout<<"D destructor"<<endl; 
    } 
}; 

Wenn Sie das tun:

B *pD = new D(); 
delete pD; 

Dann, wenn Sie kein virtuelles destructor hatte in B würde nur ~ B() aufgerufen werden. Da Sie jedoch einen virtuellen Destruktor haben, wird zuerst ~ D() und dann ~ B() aufgerufen.

+12

Bitte die Programm (Pseudo-) Ausgabe einbeziehen. Es wird dem Leser helfen. –

6

Nein. Es wird automatisch aufgerufen.

25

Was die anderen sagten, aber beachten Sie auch, dass Sie den Destruktor in der abgeleiteten Klasse nicht virtuell deklarieren müssen. Sobald Sie wie in der Basisklasse einen virtuellen Destruktor deklarieren, werden alle abgeleiteten Destruktoren virtuell, unabhängig davon, ob Sie sie deklarieren oder nicht. Mit anderen Worten:

struct A { 
    virtual ~A() {} 
}; 

struct B : public A { 
    virtual ~B() {} // this is virtual 
}; 

struct C : public A { 
    ~C() {}   // this is virtual too 
}; 
+1

Was passiert, wenn ~ B nicht als virtuell deklariert wird? Ist ~ C immer noch virtuell? – Will

+4

Ja. Wenn eine virtuelle Methode (jeder, nicht nur der Destruktor) als virtuell deklariert wird, sind alle Überschreibungen dieser Methode in abgeleiteten Klassen automatisch virtuell. In diesem Fall gilt dies auch dann, wenn Sie ~ B virtual nicht deklarieren, und auch ~ C. – boycy

+1

Im Gegensatz zu anderen überschriebenen Methoden, die denselben Namen und dieselben Parameter wie die entsprechenden Methoden in der Basisklasse haben, ist der Name des Destruktors jedoch unterschiedlich. @boycy –

9

No. Im Gegensatz zu anderen virtuellen Methoden, in denen Sie explizit die Basismethode aus den abgeleiteten zu ‚Kette‘ den Anruf nennen würden, erzeugt die Compiler Code, um die Destruktoren in der umgekehrten Reihenfolge zu nennen, in denen ihre Konstruktoren wurden aufgerufen.

2

Nein, rufen Sie nie die bese Klassendestruktor, ist es immer automatisch wie andere haben darauf hingewiesen genannt wird, aber hier ist der Beweis Konzept mit den Ergebnissen:

class base { 
public: 
    base() 
    { 
     cout << __FUNCTION__ << endl; 
    } 
    ~base() 
    { 
     cout << __FUNCTION__ << endl; 
    } 
}; 

class derived : public base { 
public: 
    derived() 
    { 
     cout << __FUNCTION__ << endl; 
    } 
    ~derived() 
    { 
     cout << __FUNCTION__ << endl; 
    } // adding call to base::~base() here results in double call to base destructor 
}; 


int main() 
{ 
    cout << "case 1, declared as local variable on stack" << endl << endl; 
    { 
     derived d1; 
    } 

    cout << endl << endl; 

    cout << "case 2, created using new, assigned to derive class" << endl << endl; 
    derived * d2 = new derived; 
    delete d2; 

    cout << endl << endl; 

    cout << "case 3, created with new, assigned to base class" << endl << endl; 
    base * d3 = new derived; 
    delete d3; 

    cout << endl; 

    return 0; 
} 

Die Ausgabe lautet:

case 1, declared as local variable on stack 

base::base 
derived::derived 
derived::~derived 
base::~base 


case 2, created using new, assigned to derive class 

base::base 
derived::derived 
derived::~derived 
base::~base 


case 3, created with new, assigned to base class 

base::base 
derived::derived 
base::~base 

Press any key to continue . . . 

Wenn Sie den Basisklasse-Destruktor als virtuell festlegen, dann sollten die Ergebnisse gleich sein wie in Fall 1 & 2.

Verwandte Themen