ChatGPT解决这个技术问题 Extra ChatGPT

Do I need to explicitly call the base virtual destructor?

When overriding a class in C++ (with a virtual destructor) I am implementing the destructor again as virtual on the inheriting class, but do I need to call the base destructor?

If so I imagine it's something like this...

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

    // Some destructing specific to MyChildClass
}

Am I right?


L
Lou Franco

No, destructors are called automatically in the reverse order of construction. (Base classes last). Do not call base class destructors.


What about pure virtual destructors? My linker is trying to call it at the end of my inherited class's non-virtual destructor;
you can't have a pure virtual destructor without a body. Just give it an empty body. With a regular pure virtual method, the overriding function is called instead, with destructors, they are all called, so you have to provide a body. The =0 just means that it must be overridden, so still a useful construct if you need it.
This question might be related and help questions/15265106/c-a-missing-vtable-error.
Why doesn’t Nick Bolton’s code cause a segmentation fault although it calls the base destructor twice, while calling delete on a pointer to the base class twice does cause a segmentation fault?
You are not guaranteed a segmentation fault with any wrong code. Also, calling a destructor does not release memory.
C
Community

No you don't need to call the base destructor, a base destructor is always called for you by the derived destructor. Please see my related answer here for order of destruction.

To understand why you want a virtual destructor in the base class, please see the code below:

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


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

When you do:

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

Then if you did not have a virtual destructor in B, only ~B() would be called. But since you have a virtual destructor, first ~D() will be called, then ~B().


Please include the program (pseudo) output. it will help reader.
@KuldeepSinghDhaka The reader can see it live at wandbox.org/permlink/KQtbZG1hjVgceSlO.
W
Wodzu

What the others said, but also note that you do not have to declare the destructor virtual in the derived class. Once you declare a destructor virtual, as you do in the base class, all derived destructors will be virtual whether you declare them so or not. In other words:

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

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

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

what if ~B is not declared virtual? Is ~C still virtual?
Yes. When a virtual method (any, not just the destructor) is declared virtual, all overrides of that method in derived classes are automatically virtual. In this case, even if you don't declare ~B virtual, it still is, and so is ~C.
But unlike other overridden methods having the same name and parameters of their corresponding methods in the base class, the destructor name is different.Will it matter? @boycy
@YuanWen no it won't, the (one and only) derived destructor always overrides its base class's (one and only) destructor.
A
Adarsh Kumar

Destructors in C++ automatically gets called in the order of their constructions (Derived then Base) only when the Base class destructor is declared virtual.

If not, then only the base class destructor is invoked at the time of object deletion.

Example: Without virtual Destructor

#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;

}

Output

Base Constructor
Derived Constructor
Base Destructor

Example: With Base virtual Destructor

#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;

}

Output

Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

It is recommended to declare base class destructor as virtual otherwise, it causes undefined behavior.

Reference: Virtual Destructor


This is a very important note about virtual or not virtual. Thank you for providing this answer.
M
Michel Keijzers

No, you never call the base class destructor, it is always called automatically like others have pointed out but here is proof of concept with results:

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;
}

The output is:

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 . . .

If you set the base class destructor as virtual which one should, then case 3 results would be same as case 1 & 2.


Good illustration. If you try to call base class destructor from the derived class you should get an compiler error similar to "error: no matching function for call to ‘BASE::BASE()’ ~BASE();" At least this is the behavior from my g++ 7.x compiler.
i
itsmatt

No. Unlike other virtual methods, where you would explicitly call the Base method from the Derived to 'chain' the call, the compiler generates code to call the destructors in the reverse order in which their constructors were called.


B
Benoît

No. It's automatically called.