1614

I have a solid understanding of most OOP theory but the one thing that confuses me a lot is virtual destructors.

I thought that the destructor always gets called no matter what and for every object in the chain.

When are you meant to make them virtual and why?

asmmo
  • 6,409
  • 1
  • 7
  • 22
Lodle
  • 28,027
  • 19
  • 59
  • 89
  • 6
    See this: [Virtual Destructor](http://stackoverflow.com/questions/353817/should-every-class-have-a-virtual-destructor) – Naveen Jan 20 '09 at 13:04
  • 156
    Every destructor _down_ gets called no matter what. `virtual` makes sure it starts at the top instead of the middle. – Mooing Duck Jun 29 '13 at 00:32
  • 15
    related question: [When should you not use virtual destructors?](http://stackoverflow.com/questions/300986/when-should-you-not-use-virtual-destructors) – Eitan T Aug 04 '13 at 16:39
  • @MooingDuck that's somewhat misleading comment. – Euri Pinhollow Jul 30 '17 at 14:34
  • @EuriPinhollow Mind elaborating? – Franklin Yu Nov 07 '17 at 22:02
  • 1
    @FranklinYu it's good that you asked because now I can't see any issue with that comment (except trying to give answer in comments). – Euri Pinhollow Nov 08 '17 at 07:02
  • @FranklinYu I probably thought about that there should be more specific claim (i.e. when destruction can start in the middle of inheritance tree instead of top) but that's what answers already elaborate. – Euri Pinhollow Nov 08 '17 at 07:07
  • I'm also confused by @MooingDuck 's answer. Shouldn't it be _up_ instead of _down_, if you use the notion of subclass (under) and superclass (above)? – Nibor Jun 20 '19 at 09:31
  • 1
    @Nibor: Yes, _if you use that notion_. About half the people I talk to view superclasses as "above", and half view superclasses as "below", so both are conflicting standards, which makes everything confusing. I think superclass as "above" is slightly more common, but that's not the way I was taught :( – Mooing Duck Jun 20 '19 at 17:09
  • this article might help. https://medium.com/@tunvirrahmantusher/a-virtual-constructor-is-not-possible-but-virtual-destructor-is-possible-1cc4e67c7aca – Tunvir Rahman Tusher Dec 26 '19 at 11:54

17 Answers17

1682

Virtual destructors are useful when you might potentially delete an instance of a derived class through a pointer to base class:

class Base 
{
    // some virtual methods
};

class Derived : public Base
{
    ~Derived()
    {
        // Do some important cleanup
    }
};

Here, you'll notice that I didn't declare Base's destructor to be virtual. Now, let's have a look at the following snippet:

Base *b = new Derived();
// use b
delete b; // Here's the problem!

Since Base's destructor is not virtual and b is a Base* pointing to a Derived object, delete b has undefined behaviour:

[In delete b], if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.

In most implementations, the call to the destructor will be resolved like any non-virtual code, meaning that the destructor of the base class will be called but not the one of the derived class, resulting in a resources leak.

To sum up, always make base classes' destructors virtual when they're meant to be manipulated polymorphically.

If you want to prevent the deletion of an instance through a base class pointer, you can make the base class destructor protected and nonvirtual; by doing so, the compiler won't let you call delete on a base class pointer.

You can learn more about virtuality and virtual base class destructor in this article from Herb Sutter.

einpoklum
  • 86,754
  • 39
  • 223
  • 453
Luc Touraille
  • 72,907
  • 15
  • 82
  • 134
  • 208
    This would explain why i had massive leaks using a factory i made before. All makes sense now. Thanks – Lodle Jan 20 '09 at 13:08
  • 11
    Well, this is a bad example as there are no data members. What if `Base` and `Derived` have _all_ automatic storage variables? ie there is no "special" or additional custom code to execute in the destructor. Is it ok then to leave off writing any destructors at all? Or will the derived class _still_ have a memory leak? – bobobobo Jul 08 '12 at 18:27
  • 4
    [Wait, it will be undefined behavior](http://stackoverflow.com/questions/2100644/will-using-delete-with-a-base-class-pointer-cause-a-memory-leak) – bobobobo Jul 08 '12 at 18:29
  • @workmad3 non-virtual is not necessary for that, is it? Useless maybe, but not required to be absent. – Steven Kramer Mar 14 '14 at 20:44
  • when there are only simple data types (no pointers for example), do we still expect to have memory leak if not using virtual destructors ? – ransh Feb 15 '15 at 07:20
  • 1
    @ransh: as @bobobobo already said in a previous comment, even if the classes have no member variables, calling `delete` on a `Base*` that points to a `Derived` object is undefined behavior. This means that the program can do anything, including leaking memory. – Luc Touraille Feb 16 '15 at 07:48
  • 35
    From the Herb Sutter's article: "Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual." – Sundae Feb 09 '16 at 08:22
  • 4
    Also from the article - 'if you delete polymorphically without a virtual destructor, you summon the dreaded specter of "undefined behavior," a specter I personally would rather not meet in even a moderately well-lit alley, thank you very much.' lol – Bondolin Feb 29 '16 at 14:30
  • 1
    @Sundae Kindly explain the `protected and non-virtual part`. – ajaysinghnegi Jul 26 '19 at 05:49
  • @Jos: From the article: "In brief, then, you're left with one of two situations. Either: a) you want to allow polymorphic deletion through a base pointer, in which case the destructor must be virtual and public; or b) you don't, in which case the destructor should be nonvirtual and protected, the latter to prevent the unwanted usage." – Sundae Aug 05 '19 at 13:36
  • To clarify, it sounds like a virtual destructor is needed if the type will be passed to `delete` when it was allocated as a derived type. The derived type does _not_ need a virtual destructor, unless the same applies to it. So a `final` class never needs a virtual destructor, even if it derives from a class that has one. – fuzzyTew Mar 22 '20 at 14:34
  • 2
    @fuzzyTew If a class D derives from a class B with a virtual destructor, then D has a virtual destructor as well, even if it doesn't declare one explicitly. Most of the time only the class at the top of the hierarchy needs to declare a virtual destructor, not the rest of the hierarchy. – Luc Touraille Mar 24 '20 at 07:40
  • @Luc Touraille: yes, your conclusion solves my confusion. Any non-abstract class can always be instantiated. So to prevent this 'undefined behavior', any non-abstract class should always be defined with virtual destructor. But most of the classes I worked with do not have a virtual destructor at all. So maybe, one of their base classes have one already! – Chuong Le Jan 21 '21 at 09:24
248

A virtual constructor is not possible but virtual destructor is possible. Let us experiment.......

#include <iostream>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

The above code output the following:

Base Constructor Called
Derived constructor called
Base Destructor called

The construction of derived object follow the construction rule but when we delete the "b" pointer(base pointer) we have found that only the base destructor is called. But this must not happen. To do the appropriate thing, we have to make the base destructor virtual. Now let see what happens in the following:

#include <iostream>

using namespace std;

class Base
{ 
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    virtual ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

The output changed as following:

Base Constructor Called
Derived Constructor called
Derived destructor called
Base destructor called

So the destruction of the base pointer (which takes an allocation on derived object!) follows the destruction rule, i.e first the Derived, then the Base. On the other hand, there is nothing like a virtual constructor.

erdostamasa
  • 357
  • 1
  • 14
Tunvir Rahman Tusher
  • 5,542
  • 2
  • 33
  • 29
  • 1
    " virtual constructor is not possible" means you need not write virtual constructor by your own. Construction of derived object must follow the chain of construction from derived to base. So you need not write the virtual keyword for your constructor. Thanks – Tunvir Rahman Tusher Apr 19 '13 at 06:50
  • 4
    @Murkantilism, "virtual constructors cannot be done" is true indeed. A constructor cannot be marked virtual. – cmeub Apr 21 '13 at 20:09
  • 1
    @cmeub, But there is an idiom to achieve what you would want from a virtual constructor. See http://www.parashift.com/c++-faq-lite/virtual-ctors.html – cape1232 Oct 03 '13 at 12:58
  • @TunvirRahmanTusher could you please explain why the Base Destructor is called?? – rimalroshan Nov 11 '17 at 08:49
  • @rimiro Its automatic by c++.you can follow the link https://stackoverflow.com/questions/677620/do-i-need-to-explicitly-call-the-base-virtual-destructor – Tunvir Rahman Tusher Nov 11 '17 at 12:01
205

Declare destructors virtual in polymorphic base classes. This is Item 7 in Scott Meyers' Effective C++. Meyers goes on to summarize that if a class has any virtual function, it should have a virtual destructor, and that classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors.

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
  • 16
    +"If a class has any virtual function, it should have a virtual destructor, and that classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors.": Are there cases in which it makes sense to break this rule? If not, would it make sense to have the compiler check this condition and issue an error is it is not satisfied? – Giorgio May 06 '12 at 09:29
  • @Giorgio I don't know of any exceptions to the rule. But I wouldn't rate myself as a C++ expert, so you may want to post this as a separate question. A compiler warning (or a warning from a static analysis tool) makes sense to me. – Bill the Lizard May 06 '12 at 13:08
  • 12
    Classes can be designed not to be deleted through a certain type's pointer, yet still have virtual functions - typical example is a callback interface. One does not delete his implementation through a callback interface pointer as that's only for subscribing, but it does have virtual functions. – dascandy Jan 15 '16 at 05:05
  • 5
    @dascandy Exactly - that or all the _many_ other situations where we use polymorphic behaviour but don't perform storage management via pointers - e.g. maintaining automatic or static-duration objects, with pointers only used as observation routes. No need/purpose in implementing a virtual destructor in any such cases. Since we're just quoting people here, I prefer Sutter from above: "Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual." The latter ensures anyone accidentally trying to delete via a base pointer is shown the error of their ways – underscore_d Apr 23 '16 at 15:58
  • 1
    @Giorgio There is actually a trick one can use and avoid a virtual call to a destructor: bind via a const reference a derived object to a base, like `const Base& = make_Derived();`. In this case, the destructor of the `Derived` prvalue will be called, even if it's not virtual, so one saves the overhead introduced by vtables/vpointers. Of course the scope is quite limited. Andrei Alexandrescu mentioned this in his book [Modern C++ Design](https://en.wikipedia.org/wiki/Modern_C%2B%2B_Design). – vsoftco Nov 02 '16 at 20:06
  • @Giorgio there is a warning in gcc for just this situation. dascandy they initially failed to consider your point as [documented here](https://stackoverflow.com/a/127516/622049). – davidvandebunte Nov 24 '17 at 23:12
  • Why do things work if there is no virtual method without a polymorphic destructor? EDIT answer: they don't, but in that case, you would never need to write `Base *b = new Derived1`, which is the source of all problems, but rather `Derived1 *b = new Derived1`. Also, without `new`, there can be no problems, as the compiler always knows the real type of whatever goes out of scope. – Ciro Santilli新疆棉花TRUMP BAN BAD Feb 14 '18 at 14:35
48

Also be aware that deleting a base class pointer when there is no virtual destructor will result in undefined behavior. Something that I learned just recently:

How should overriding delete in C++ behave?

I've been using C++ for years and I still manage to hang myself.

Community
  • 1
  • 1
BigSandwich
  • 2,618
  • 2
  • 20
  • 26
  • I had a look at that question of yours and saw that you had declared the base destructor as virtual. So does "deleting a base class pointer when there is no virtual destructor will result in undefined behavior" stay valid with respect to that question of yours? Since, in that question, when you called delete, the derived class (created by its new operator) is checked for a compatible version first. Since it found one there, it was called. So, don't you think it would be better to say as "deleting a base class pointer when there is no destructor will result in undefined behavior"? – ubuntugod Feb 23 '16 at 07:09
  • Thats pretty much the same thing. The default constructor is not virtual. – BigSandwich Feb 26 '16 at 23:30
43

Make the destructor virtual whenever your class is polymorphic.

Dana
  • 28,425
  • 17
  • 58
  • 72
yesraaj
  • 42,284
  • 65
  • 185
  • 246
16

Calling destructor via a pointer to a base class

struct Base {
  virtual void f() {}
  virtual ~Base() {}
};

struct Derived : Base {
  void f() override {}
  ~Derived() override {}
};

Base* base = new Derived;
base->f(); // calls Derived::f
base->~Base(); // calls Derived::~Derived

Virtual destructor call is no different from any other virtual function call.

For base->f(), the call will be dispatched to Derived::f(), and it's the same for base->~Base() - its overriding function - the Derived::~Derived() will be called.

Same happens when destructor is being called indirectly, e.g. delete base;. The delete statement will call base->~Base() which will be dispatched to Derived::~Derived().

Abstract class with non-virtual destructor

If you are not going to delete object through a pointer to its base class - then there is no need to have a virtual destructor. Just make it protected so that it won't be called accidentally:

// library.hpp

struct Base {
  virtual void f() = 0;

protected:
  ~Base() = default;
};

void CallsF(Base& base);
// CallsF is not going to own "base" (i.e. call "delete &base;").
// It will only call Base::f() so it doesn't need to access Base::~Base.

//-------------------
// application.cpp

struct Derived : Base {
  void f() override { ... }
};

int main() {
  Derived derived;
  CallsF(derived);
  // No need for virtual destructor here as well.
}
Abyx
  • 10,859
  • 4
  • 36
  • 74
  • Is it necessary to explicitly declare `~Derived()` in all derived classes, even if it's just `~Derived() = default`? Or is that implied by the language (making it safe to omit)? – Ponkadoodle Aug 18 '16 at 15:20
  • @Wallacoloo no, only declare it when it's necessary. E.g. to put in `protected` section, or to ensure that it's virtual by using `override`. – Abyx Aug 18 '16 at 17:51
11

To be simple, Virtual destructor is to destruct the resources in a proper order, when you delete a base class pointer pointing to derived class object.

 #include<iostream>
 using namespace std;
 class B{
    public:
       B(){
          cout<<"B()\n";
       }
       virtual ~B(){ 
          cout<<"~B()\n";
       }
 };
 class D: public B{
    public:
       D(){
          cout<<"D()\n";
       }
       ~D(){
          cout<<"~D()\n";
       }
 };
 int main(){
    B *b = new D();
    delete b;
    return 0;
 }

OUTPUT:
B()
D()
~D()
~B()

==============
If you don't give ~B()  as virtual. then output would be 
B()
D()
~B()
where destruction of ~D() is not done which leads to leak

Prakash GiBBs
  • 217
  • 2
  • 12
  • Not have the base virtual destructor and calling `delete` on a base pointer leads to undefined behavior. – James Adkison Oct 13 '16 at 20:00
  • @JamesAdkison why does it lead to undefined behaviour?? – rimalroshan Nov 11 '17 at 11:06
  • @rimiro [It's what the standard says](https://stackoverflow.com/questions/8772227/deleting-a-derived-object-via-a-pointer-to-its-base-class#comment48280738_8772227). I don't have a copy but the link takes you to a comment where someone references the location within the standard. – James Adkison Nov 11 '17 at 13:52
  • @rimiro "If deletion, therefore, can be performed polymorphically through the base class interface, then it must behave virtually and must be virtual. Indeed, the language requires it - if you delete polymorphically without a virtual destructor, you summon the dreaded specter of "undefined behavior," a specter I personally would rather not meet in even a moderately well-lit alley, thank you very much." (http://www.gotw.ca/publications/mill18.htm) -- Herb Sutter – James Adkison Nov 11 '17 at 13:54
10

Virtual keyword for destructor is necessary when you want different destructors should follow proper order while objects is being deleted through base class pointer. for example:

Base *myObj = new Derived();
// Some code which is using myObj object
myObj->fun();
//Now delete the object
delete myObj ; 

If your base class destructor is virtual then objects will be destructed in a order(firstly derived object then base ). If your base class destructor is NOT virtual then only base class object will get deleted(because pointer is of base class "Base *myObj"). So there will be memory leak for derived object.

akay
  • 3
  • 2
Mukul Kashmira
  • 149
  • 1
  • 7
9

I like to think about interfaces and implementations of interfaces. In C++ speak interface is pure virtual class. Destructor is part of the interface and expected to implemented. Therefore destructor should be pure virtual. How about constructor? Constructor is actually not part of the interface because object is always instantiated explicitly.

  • 2
    It's a different perspective on the same question. If we think in terms of interfaces instead of base class vs derived class then it's natural conclusion: if it's a part of the interface than make it virtual. If it's not don't. – Dragan Ostojic Nov 09 '12 at 18:58
  • 2
    +1 for stating the similarity of the OO concept of **interface** and a C++ **pure virtual class**. Regarding *destructor is expected to be implemented*: that is often unnecessary. Unless a class is managing a resource such as raw dynamically allocated memory (e.g., not via a smart pointer), a file handle or a database handle, using the default destructor created by the compiler is fine in derived classes. And note that if a destructor (or any function) is declared `virtual` in a base class, it is automatically `virtual` in a derived class, even if it is not declared so. – DavidRR Jul 11 '13 at 13:22
  • This misses the crucial detail that the destructor is _not necessarily_ part of the interface. One can easily program classes that have polymorphic functions but which the caller does not manage/is not allowed to delete. Then a virtual destructor has no purpose. Of course, to ensure this, the non-virtual - probably default - destructor should be non-public. If I had to guess, I'd say such classes are more often used internally to projects, but that doesn't make them any less relevant as an example/nuance in all this. – underscore_d Apr 23 '16 at 16:12
4

What is a virtual destructor or how to use virtual destructor

A class destructor is a function with same name of the class preceding with ~ that will reallocate the memory that is allocated by the class. Why we need a virtual destructor

See the following sample with some virtual functions

The sample also tell how you can convert a letter to upper or lower

#include "stdafx.h"
#include<iostream>
using namespace std;
// program to convert the lower to upper orlower
class convertch
{
public:
  //void convertch(){};
  virtual char* convertChar() = 0;
  ~convertch(){};
};

class MakeLower :public convertch
{
public:
  MakeLower(char *passLetter)
  {
    tolower = true;
    Letter = new char[30];
    strcpy(Letter, passLetter);
  }

  virtual ~MakeLower()
  {
    cout<< "called ~MakeLower()"<<"\n";
    delete[] Letter;
  }

  char* convertChar()
  {
    size_t len = strlen(Letter);
    for(int i= 0;i<len;i++)
      Letter[i] = Letter[i] + 32;
    return Letter;
  }

private:
  char *Letter;
  bool tolower;
};

class MakeUpper : public convertch
{
public:
  MakeUpper(char *passLetter)
  {
    Letter = new char[30];
    toupper = true;
    strcpy(Letter, passLetter);
  }

  char* convertChar()
  {   
    size_t len = strlen(Letter);
    for(int i= 0;i<len;i++)
      Letter[i] = Letter[i] - 32;
    return Letter;
  }

  virtual ~MakeUpper()
  {
    cout<< "called ~MakeUpper()"<<"\n";
    delete Letter;
  }

private:
  char *Letter;
  bool toupper;
};


int _tmain(int argc, _TCHAR* argv[])
{
  convertch *makeupper = new MakeUpper("hai"); 
  cout<< "Eneterd : hai = " <<makeupper->convertChar()<<" ";     
  delete makeupper;
  convertch *makelower = new MakeLower("HAI");;
  cout<<"Eneterd : HAI = " <<makelower->convertChar()<<" "; 
  delete makelower;
  return 0;
}

From the above sample you can see that the destructor for both MakeUpper and MakeLower class is not called.

See the next sample with the virtual destructor

#include "stdafx.h"
#include<iostream>

using namespace std;
// program to convert the lower to upper orlower
class convertch
{
public:
//void convertch(){};
virtual char* convertChar() = 0;
virtual ~convertch(){}; // defined the virtual destructor

};
class MakeLower :public convertch
{
public:
MakeLower(char *passLetter)
{
tolower = true;
Letter = new char[30];
strcpy(Letter, passLetter);
}
virtual ~MakeLower()
{
cout<< "called ~MakeLower()"<<"\n";
      delete[] Letter;
}
char* convertChar()
{
size_t len = strlen(Letter);
for(int i= 0;i<len;i++)
{
Letter[i] = Letter[i] + 32;

}

return Letter;
}

private:
char *Letter;
bool tolower;

};
class MakeUpper : public convertch
{
public:
MakeUpper(char *passLetter)
{
Letter = new char[30];
toupper = true;
strcpy(Letter, passLetter);
}
char* convertChar()
{

size_t len = strlen(Letter);
for(int i= 0;i<len;i++)
{
Letter[i] = Letter[i] - 32;
}
return Letter;
}
virtual ~MakeUpper()
{
      cout<< "called ~MakeUpper()"<<"\n";
delete Letter;
}
private:
char *Letter;
bool toupper;
};


int _tmain(int argc, _TCHAR* argv[])
{

convertch *makeupper = new MakeUpper("hai");

cout<< "Eneterd : hai = " <<makeupper->convertChar()<<" \n";

delete makeupper;
convertch *makelower = new MakeLower("HAI");;
cout<<"Eneterd : HAI = " <<makelower->convertChar()<<"\n ";


delete makelower;
return 0;
}

The virtual destructor will call explicitly the most derived run time destructor of class so that it will be able to clear the object in a proper way.

Or visit the link

https://web.archive.org/web/20130822173509/http://www.programminggallery.com/article_details.php?article_id=138

peak
  • 72,551
  • 14
  • 101
  • 128
4

I think the core of this question is about virtual methods and polymorphism, not the destructor specifically. Here is a clearer example:

class A
{
public:
    A() {}
    virtual void foo()
    {
        cout << "This is A." << endl;
    }
};

class B : public A
{
public:
    B() {}
    void foo()
    {
        cout << "This is B." << endl;
    }
};

int main(int argc, char* argv[])
{
    A *a = new B();
    a->foo();
    if(a != NULL)
    delete a;
    return 0;
}

Will print out:

This is B.

Without virtual it will print out:

This is A.

And now you should understand when to use virtual destructors.

Peter Hall
  • 36,534
  • 10
  • 79
  • 144
gonjay
  • 657
  • 1
  • 6
  • 12
  • No, this only retreads the utter basics of virtual functions, totally ignoring the nuance of when/why the destructor should be one - which isn't as intuitive, hence why the OP asked the question. (Also, why the unnecessary dynamic allocation here? Just do `B b{}; A& a{b}; a.foo();`. Checking for `NULL` - which should be `nullptr` - before `delete`ing - with incorrect indendation - is not required: `delete nullptr;` is defined as a no-op. If anything, you should have checked this before calling `->foo()`, as otherwise undefined behaviour can occur if the `new` somehow failed.) – underscore_d Apr 23 '16 at 16:15
  • 2
    It is safe to call `delete` on a `NULL` pointer (i.e., you don't need the `if (a != NULL)` guard). – James Adkison Oct 13 '16 at 19:57
  • @SaileshD Yes, I know. That is what I said in [my comment](https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors/23723229?noredirect=1#comment67336865_23723229) – James Adkison Apr 18 '18 at 16:02
4

Virtual base class destructors are "best practice" - you should always use them to avoid (hard to detect) memory leaks. Using them, you can be sure all destructors in the inheritance chain of your classes are beeing called (in proper order). Inheriting from a base class using virtual destructor makes the destructor of the inheriting class automatically virtual, too (so you do not have to retype 'virtual' in the inheriting class destructor declaration).

Trantor
  • 752
  • 1
  • 7
  • 24
4

If you use shared_ptr(only shared_ptr, not unique_ptr), you don't have to have the base class destructor virtual:

#include <iostream>
#include <memory>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    ~Base(){ // not virtual
        cout << "Base Destructor called\n";
    }
};

class Derived: public Base
{
public:
    Derived(){
        cout << "Derived constructor called\n";
    }
    ~Derived(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    shared_ptr<Base> b(new Derived());
}

output:

Base Constructor Called
Derived constructor called
Derived destructor called
Base Destructor called
Zhenxiao Hao
  • 5,975
  • 7
  • 25
  • 46
  • 1
    Though this is possible, I would discourage anyone from using this. The overhead of a virtual destructor is miniscule and this just makes it possible to mess up, specially by a less experienced programmer, who doesn't know this. That little `virtual` keyword could save you from a lot of agony. – Michal Štein Mar 21 '20 at 12:18
2

when you need to call derived class destructor from base class. you need to declare virtual base class destructor in base class.

user2641018
  • 108
  • 5
1

I thought it would be beneficial to discuss the "undefined" behavior, or at least the "crash" undefined behavior that may occur when deleting through a base class(/struct) without a virtual destructor, or more precisely no vtable. The code below list a few simple structs (the same would be true for classes).

#include <iostream>
using namespace std;

struct a
{
    ~a() {}

    unsigned long long i;
};

struct b : a
{
    ~b() {}

    unsigned long long j;
};

struct c : b
{
    ~c() {}

    virtual void m3() {}

    unsigned long long k;
};

struct d : c
{
    ~d() {}

    virtual void m4() {}

    unsigned long long l;
};

int main()
{
    cout << "sizeof(a): " << sizeof(a) << endl;
    cout << "sizeof(b): " << sizeof(b) << endl;
    cout << "sizeof(c): " << sizeof(c) << endl;
    cout << "sizeof(d): " << sizeof(d) << endl;

    // No issue.

    a* a1 = new a();
    cout << "a1: " << a1 << endl;
    delete a1;

    // No issue.

    b* b1 = new b();
    cout << "b1: " << b1 << endl;
    cout << "(a*) b1: " << (a*) b1 << endl;
    delete b1;

    // No issue.

    c* c1 = new c();
    cout << "c1: " << c1 << endl;
    cout << "(b*) c1: " << (b*) c1 << endl;
    cout << "(a*) c1: " << (a*) c1 << endl;
    delete c1;

    // No issue.

    d* d1 = new d();
    cout << "d1: " << d1 << endl;
    cout << "(c*) d1: " << (c*) d1 << endl;
    cout << "(b*) d1: " << (b*) d1 << endl;
    cout << "(a*) d1: " << (a*) d1 << endl;
    delete d1;

    // Doesn't crash, but may not produce the results you want.

    c1 = (c*) new d();
    delete c1;

    // Crashes due to passing an invalid address to the method which
    // frees the memory.

    d1 = new d();
    b1 = (b*) d1;
    cout << "d1: " << d1 << endl;
    cout << "b1: " << b1 << endl;
    delete b1;  

/*

    // This is similar to what's happening above in the "crash" case.

    char* buf = new char[32];
    cout << "buf: " << (void*) buf << endl;
    buf += 8;
    cout << "buf after adding 8: " << (void*) buf << endl;
    delete buf;
*/
}

I'm not suggesting whether you need virtual destructors or not, though I think in general it's a good practice to have them. I'm just pointing out the reason you may end up with a crash if your base class(/struct) does not have a vtable and your derived class(/struct) does and you delete an object via a base class(/struct) pointer. In this case, the address you pass to the heap's free routine is invalid and thus the reason for the crash.

If you run the above code you'll see clearly when the issue occurs. When the this pointer of the base class(/struct) is different from the this pointer of the derived class(/struct) you're going to run into this problem. In the sample above, struct a and b don't have vtables. structs c and d do have vtables. Thus an a or b pointer to a c or d object instance will be fixed up to account for the vtable. If you pass this a or b pointer to delete it will crash due to the address being invalid to the heap's free routine.

If you plan to delete derived instances which have vtables from base class pointers, you need to ensure the base class has a vtable. One way to do that is to add a virtual destructor, which you might want anyway to properly clean up resources.

nickdu
  • 567
  • 4
  • 15
0

A basic definition about virtual is it determines if a member function of a class can be over-ridden in its derived classes.

A class's D-tor is called basically at the end of the scope, but there is a problem, for example when we define an instance on the Heap (dynamic allocation), we should delete it manually.

As soon as the instruction get executed, the base class destructor get called, but not for the derived one.

A Pratical example is when, in control field, you have to manipulate effectors, actuators.

At the end of the scope, if the destructor of one of the power elements (Actuator), isn't called, there will be fatal consequences.

#include <iostream>

class Mother{

public:

    Mother(){

          std::cout<<"Mother Ctor"<<std::endl;
    }

    virtual~Mother(){

        std::cout<<"Mother D-tor"<<std::endl;
    }


};

class Child: public Mother{

    public:

    Child(){

        std::cout<<"Child C-tor"<<std::endl;
    }

    ~Child(){

         std::cout<<"Child D-tor"<<std::endl;
    }
};

int main()
{

    Mother *c = new Child();
    delete c;

    return 0;
}
rekkalmd
  • 133
  • 1
  • 12
-1

Any class that is inherited publicly, polymorphic or not, should have a virtual destructor. To put another way, if it can be pointed to by a base class pointer, its base class should have a virtual destructor.

If virtual, the derived class destructor gets called, then the base class constructor. If not virtual, only the base class destructor gets called.

Syed H
  • 195
  • 1
  • 1
  • 8
  • I would say this is only necessary "if it can be pointed to by a base class pointer" _and_ can be publically deleted. But I guess it doesn't hurt to get into the habit of adding virtual dtors in case they might become needed later. – underscore_d Apr 23 '16 at 16:21