Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I declare a virtual destructor for an abstract class in C++?

People also ask

Why should destructors be declared virtual?

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

Can abstract class have destructor?

You can create an abstract base class with only a virtual destructor.

Why is it necessary to have a destructor for a class?

Destructors are usually used to deallocate memory and do other cleanup for a class object and its class members when the object is destroyed. A destructor is called for a class object when that object passes out of scope or is explicitly deleted.


It's even more important for an interface. Any user of your class will probably hold a pointer to the interface, not a pointer to the concrete implementation. When they come to delete it, if the destructor is non-virtual, they will call the interface's destructor (or the compiler-provided default, if you didn't specify one), not the derived class's destructor. Instant memory leak.

For example

class Interface
{
   virtual void doSomething() = 0;
};

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

void myFunc(void)
{
   Interface* p = new Derived();
   // The behaviour of the next line is undefined. It probably 
   // calls Interface::~Interface, not Derived::~Derived
   delete p; 
}

The answer to your question is often, but not always. If your abstract class forbids clients to call delete on a pointer to it (or if it says so in its documentation), you are free to not declare a virtual destructor.

You can forbid clients to call delete on a pointer to it by making its destructor protected. Working like this, it is perfectly safe and reasonable to omit a virtual destructor.

You will eventually end up with no virtual method table, and end up signalling your clients your intention on making it non-deleteable through a pointer to it, so you have indeed reason not to declare it virtual in those cases.

[See item 4 in this article: http://www.gotw.ca/publications/mill18.htm]


I decided to do some research and try to summarise your answers. The following questions will help you to decide what kind of destructor you need:

  1. Is your class intended to be used as a base class?
    • No: Declare public non-virtual destructor to avoid v-pointer on each object of the class *.
    • Yes: Read next question.
  2. Is your base class abstract? (i.e. any virtual pure methods?)
    • No: Try to make your base class abstract by redesigning your class hierarchy
    • Yes: Read next question.
  3. Do you want to allow polymorphic deletion through a base pointer?
    • No: Declare protected virtual destructor to prevent the unwanted usage.
    • Yes: Declare public virtual destructor (no overhead in this case).

I hope this helps.

* It is important to note that there is no way in C++ to mark a class as final (i.e. non subclassable), so in the case that you decide to declare your destructor non-virtual and public, remember to explicitly warn your fellow programmers against deriving from your class.

References:

  • "S. Meyers. More Effective C++, Item 33 Addison-Wesley, 1996."
  • Herb Sutter, Virtuality, 2001
  • C++ Faq, 20.7, "When should my destructor be virtual?"
  • The answers to this question, of course.

Yes it is always important. Derived classes may allocate memory or hold reference to other resources that will need to be cleaned up when the object is destroyed. If you do not give your interfaces/abstract classes virtual destructors, then every time you delete a derived class instance via a base class handle your derived class' destructor will not be called.

Hence, you're opening up the potential for memory leaks

class IFoo
{
  public:
    virtual void DoFoo() = 0;
};

class Bar : public IFoo
{
  char* dooby = NULL;
  public:
    virtual void DoFoo() { dooby = new char[10]; }
    void ~Bar() { delete [] dooby; }
};

IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted

It is not always required, but I find it to be good practice. What it does, is it allows a derived object to be safely deleted through a pointer of a base type.

So for example:

Base *p = new Derived;
// use p as you see fit
delete p;

is ill-formed if Base doesn't have a virtual destructor, because it will attempt to delete the object as if it were a Base *.


It's not only good practice. It is rule #1 for any class hierarchy.

  1. The base most class of a hierarchy in C++ must have a virtual destructor

Now for the Why. Take the typical animal hierarchy. Virtual destructors go through virtual dispatch just as any other method call. Take the following example.

Animal* pAnimal = GetAnimal();
delete pAnimal;

Assume that Animal is an abstract class. The only way that C++ knows the proper destructor to call is via virtual method dispatch. If the destructor is not virtual then it will simply call Animal's destructor and not destroy any objects in derived classes.

The reason for making the destructor virtual in the base class is that it simply removes the choice from derived classes. Their destructor becomes virtual by default.


The answer is simple, you need it to be virtual otherwise the base class would not be a complete polymorphic class.

    Base *ptr = new Derived();
    delete ptr; // Here the call order of destructors: first Derived then Base.

You would prefer the above deletion, but if the base class's destructor is not virtual, only the base class's destructor will be called and all data in derived class will remain undeleted.