439 Stimmen

Muss ich den virtuellen Basis-Destruktor explizit aufrufen?

Wenn ich eine Klasse in C++ überschreibe (mit einem virtuellen Destruktor), implementiere ich den Destruktor wieder als virtuell in der erbenden Klasse, aber muss ich den Destruktor der Basisklasse aufrufen?

Wenn ja, kann ich mir vorstellen, dass es ungefähr so aussieht...

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

    // Some destructing specific to MyChildClass
}

Habe ich Recht?

594voto

Lou Franco Punkte 85315

Nein, Destruktoren werden automatisch in der umgekehrten Reihenfolge der Konstruktion aufgerufen. (Basisklassen zuletzt). Rufen Sie keine Destruktoren von Basisklassen auf.

106voto

Brian R. Bondy Punkte 325712

Nein, Sie müssen den Basis-Destruktor nicht aufrufen, ein Basis-Destruktor wird immer vom abgeleiteten Destruktor für Sie aufgerufen. Zur Reihenfolge der Zerstörung siehe meine entsprechende Antwort hier .

Um zu verstehen, warum Sie einen virtuellen Destruktor in der Basisklasse benötigen, sehen Sie sich bitte den folgenden Code an:

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;

Hätten Sie keinen virtuellen Destruktor in B, würde nur ~B() aufgerufen werden. Da Sie aber einen virtuellen Destruktor haben, wird zuerst ~D() aufgerufen, dann ~B().

35voto

Was die anderen gesagt haben, aber beachten Sie auch, dass Sie den Destruktor in der abgeleiteten Klasse nicht als virtuell deklarieren müssen. Sobald Sie einen Destruktor als virtuell deklarieren, wie Sie es in der Basisklasse tun, werden alle abgeleiteten Destruktoren virtuell sein, ob Sie sie nun so 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
};

28voto

Adarsh Kumar Punkte 309

Destruktoren in C++ wird automatisch aufgerufen in der Reihenfolge ihrer Konstruktionen (Abgeleitet, dann Basis) nur, wenn der Destruktor der Basisklasse deklariert ist virtual .

Ist dies nicht der Fall, wird nur der Destruktor der Basisklasse zum Zeitpunkt des Löschens des Objekts aufgerufen.

Beispiel: Ohne virtuellen Destruktor

#include <iostream>

using namespace std;

class Base{
public:
  Base(){
    cout << "Base Constructor \n";
  }

  ~Base(){
    cout << "Base Destructor \n";
  }

};

class Derived: public Base{
public:
  int *n;
  Derived(){
    cout << "Derived Constructor \n";
    n = new int(10);
  }

  void display(){
    cout<< "Value: "<< *n << endl;
  }

  ~Derived(){
    cout << "Derived Destructor \n";
  }
};

int main() {

 Base *obj = new Derived();  //Derived object with base pointer
 delete(obj);   //Deleting object
 return 0;

}

Ausgabe

Base Constructor
Derived Constructor
Base Destructor

Beispiel: Mit virtuellem Basis-Destruktor

#include <iostream>

using namespace std;

class Base{
public:
  Base(){
    cout << "Base Constructor \n";
  }

  //virtual destructor
  virtual ~Base(){
    cout << "Base Destructor \n";
  }

};

class Derived: public Base{
public:
  int *n;
  Derived(){
    cout << "Derived Constructor \n";
    n = new int(10);
  }

  void display(){
    cout<< "Value: "<< *n << endl;
  }

  ~Derived(){
    cout << "Derived Destructor \n";
    delete(n);  //deleting the memory used by pointer
  }
};

int main() {

 Base *obj = new Derived();  //Derived object with base pointer
 delete(obj);   //Deleting object
 return 0;

}

Ausgabe

Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

Es wird empfohlen, den Destruktor der Basisklasse zu deklarieren als virtual andernfalls führt es zu undefiniertem Verhalten.

Referenz: Virtueller Destruktor

15voto

zar Punkte 10223

Nein, du rufst nie den Destruktor der Basisklasse auf, er wird immer automatisch aufgerufen, wie andere schon gesagt haben, aber hier ist der Beweis des Konzepts mit 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 ist:

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 die Basisklasse destructor als virtuelle, die man sollte, dann Fall 3 Ergebnisse wäre das gleiche wie Fall 1 & 2.

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