0

I was doing some practicing with pointers to derived classes and when I ran the code provided underneath,the output I get is

Constructor A
Constructor B
Destructor A

Could someone tell me why is B::~B() not getting invoked here?

class A {
 public:
  A() { std::cout << "Constructor A\n"; }
  ~A() { std::cout << "Destructor A\n"; }
};

class B : public A {
 public:
  B() { std::cout << "Constructor B\n"; }
  ~B() { std::cout << "Destructor B\n"; }
};

int main() {
  A* a = new B;
  delete a;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 5
    If a function is not `virtual`, it can't be called via polymorphism. The `B` and `A`'s destructor is not virtual – Alexey S. Larionov Mar 07 '22 at 20:57
  • 6
    Because you are calling `delete` on a `A*`, not a `B*`, and `A*`'s destructor is not `virtual`. The program has undefined behavior as a consequence, since the most-derived type of the object is actually `B`, not `A`. – user17732522 Mar 07 '22 at 20:57
  • 1
    The inverse question: [When to use virtual destructors?](https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors) – user4581301 Mar 07 '22 at 21:03

2 Answers2

4

The static type of the pointer a is A *.

A* a = new B;

So all called member functions using this pointer are searched in the class A.

To call the destructor of the dynamic type of the pointer, that is of the class B, you need to declare the destructor as virtual in class A. For example:

#include <iostream>

class A {
 public:
  A() { std::cout << "Constructor A\n"; }
  virtual ~A() { std::cout << "Destructor A\n"; }
};

class B : public A {
 public:
  B() { std::cout << "Constructor B\n"; }
  ~B() override { std::cout << "Destructor B\n"; }
};

int main() {
  A* a = new B;
  delete a;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
3

becuase overriden methods need to be virtual

class A{
public:
    A()
    {
        std::cout<<"Constructor A\n";
    }
    virtual ~A()
    {
        std::cout<<"Destructor A\n";
    }
};
class B : public A{
public:
    B()
    {
        std::cout<<"Constructor B\n";
    }
    virtual ~B()
    {
        std::cout<<"Destructor B\n";
    }
};
pm100
  • 48,078
  • 23
  • 82
  • 145
  • 2
    The second `virtual` is optional, but `override` may be used to prevent mistakes. – user17732522 Mar 07 '22 at 20:59
  • 1
    More specifically, *any time* you write a class with the intention that it be subclassed and used in a virtual context (i.e. through a pointer/reference to the base class), the destructor at minimum needs to be virtual, even if it's `virtual ~A() = default`. Otherwise, you'll run into problems when an instance gets `delete`d via a variable with a parent type. – Silvio Mayolo Mar 07 '22 at 20:59
  • @SilvioMayolo ... but you _can_ use polymorphism without a `virtual` destructor if the _deleter_ is stored with the object, as it is in a `std::shared_ptr` ([example](https://godbolt.org/z/ddq1aEoxe)). – Ted Lyngmo Mar 07 '22 at 21:13
  • So when I get to "delete a;" what happens is I invoke A::~A() because the pointer a doesn't know B::~B() exists,and if I override A::~A() I make it so it searches for the most derived version of the destructor and it runs into B::~B() and after it finished up with it's object A::~A() gets called? – Your FBI Agent Mar 07 '22 at 21:15
  • @YourFBIAgent yes, the clever magic of derived classes only works for virtual methods , other wise c++ just goes "well he told me this was an A object so I will call `A::~`" – pm100 Mar 07 '22 at 21:20
  • @YourFBIAgent — `delete a;` produces undefined behavior. It is not required to call `A`’s destructor. The rule is that if the code deletes an object of a derived type through a pointer to the base and the base does not have a virtual destructor the behavior is undefined. – Pete Becker Mar 07 '22 at 22:29