Question

Say we have the classes.

class A 
{
public:

   void doSomething() = 0;
   A();
   virtual ~A();

private:

   vector<SomeStuff> cont;
   bool yesNo;

}

class B: public A
{

public:

   B();
   ~B();

private:

   bool Byesno;
}

So the constructor of A gets called first and then the constructor of B gets called after that, and when we destroy B, the destructor of B gets called first and the destructor of A gets called after that. So basically, the destructor of A will delete the inherited variables of B and and the destructor of B will delete its class-specific ones. Am I right?

what I don't understand is how can we call the destructor of A if we can't even instantiate an object of type A? How does it work internally?

Was it helpful?

Solution

B is A and some more. Destructor of A will be called to ensure that A part of B is cleaned up. Your classes don't use the virtual keyword, so I'm not sure why you are wondering about virtual destructors, but since you are wondering this might help:

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

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

int main()
{
    A* obj = new B();
    delete obj;
    return 0;
}

The output as you'd expect will be

B::~B()
A::~A()

But, if you didn't declare A's destructor virtual, the output will simply be

A::~A()

So, in conclusion, if your code involves polymorphism and you want the destructor of the pointed to object to be called as opposed to the destructor of pointer's type itself, you will have to declare your base-class destructor virtual.

OTHER TIPS

Each destructor runs through three stages:

  1. user code
  2. delegate destruction of class members to the respective destructors
  3. delegate destruction of base classes to the respective destructors

The destructors for the primitive types are normally trivial, i.e. do nothing. Technically, you could think of

B::~B() { Byesno = false; }

as

B::~B()
{
    Byesno = false;  // explicit
    Byesno.~bool();  // implicit, member
    A::~A();         // implicit, base class
}


A::~A()
{
    yesNo.~bool();   // implicit, member
    cont.~vector();  // implicit, member
}

~bool() is empty and will be inlined, so the only call you can see is the one to ~vector().

All this is a separate matter from which d'tor is called. If A's d'tor is non-virtual, B's d'tor will be called only if the object being destructed is known to be a B object:

A a;
B b;
A *ap = new B;
delete ap;

This will use ~A() for the a object (correct), ~B() for the b object (also correct), and ~A() for the object pointed to by ap (incorrect, but we don't know better). If ~A() were virtual, the d'tor call itself would be looked up in the v'table, which contains a pointer to ~B() then.

It is a tiny bit more complex than that, but not much.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top