Pure virtual destructors in C++

November 13th, 2010 at 6:34 pm

To work correctly, classes with virtual methods must also have virtual destructors. Interestingly, virtual destructors can be declared pure, which can be useful in some cases.

Imagine you have a base class you want to make abstract. In this base class all methods have meaningful default implementations, and you want to allow the derived classes to inherit them as-is. However, to make a class abstract, at least one of its methods must be made pure virtual, which means the derived classes must override it. How do you make the class abstract in this case?

The answer is: declare the destructor pure virtual. This will make your class abstract without forcing you to declare any other method pure virtual.

// Abstract base class - can't be instantiated
//
class Base
{
public:
    virtual ~Base() = 0;
    virtual void method();
};

Base::~Base()
{
  // Compulsory virtual destructor definition,
  // even if it's empty
}

void Base::method()
{
  // Default implementation.
  // Derived classes can just inherit it, if needed
}

// We can now derive from Base, inheriting the
// implementation of method()
//
class Derived : public Base
{
public:
    ~Derived()
    {}
};

While defining (providing an implementation) pure virtual methods is rarely useful, you must define a pure virtual destructor. This is because the destructor of a base class is always called when a derived object is destroyed. Failing to define it will cause a link error.

Related posts:

  1. The Curiously Recurring Template Pattern in C++
  2. pure delight !! (MIX byte code, debugger and other oddities)
  3. Safely using destructors in Python
  4. Exporting C++ classes from a DLL
  5. Dependent name lookup for C++ templates

17 Responses to “Pure virtual destructors in C++”

  1. Paul BrannanNo Gravatar Says:

    I believe failing to define the destructor will cause a link error, not a compile error.

    Very well written, though. This is one of those ugly corners of C++ that the programmer shouldn’t have to know about, but does.

  2. elibenNo Gravatar Says:

    @Paul,

    Thanks! I wrote “compilation error” as a generic term for “error during the compilation process”, but thinking about this again, just going with “link error” is clearer, so I fixed the post.

  3. Mickaël WolffNo Gravatar Says:

    When you use a abstract class and want to inherit the API, you have to use public inheritence.

  4. Michal MocnyNo Gravatar Says:

    I have learned to just do this all the time for abstract base classes (ABC).

    To me, at least for my own C++, “interface” has become synonymous with “has a pure virtual destructor”. This way I never forget to (a) declare a virtual destructor, or (b) have at least one pure method.

    Important: if you want to write your ABC entirely in a header file, you need to declare your destructor definition with “inline” so as to not have multiple re-definitions.

  5. elibenNo Gravatar Says:

    @Mickaël
    Thanks – it was a typo, added the public inheritance specifier

    @Michal:
    Interesting, thanks. Indeed, there’s no harm defining it pure always in a ABC.

  6. DougNo Gravatar Says:

    I don’t think “must” is the correct word here. You have an option to not to define a Virtual desctructor. Doing would just create a bunch of leak when derived classes allocate resources which won’t get garbage collected properly.

  7. David WorkmanNo Gravatar Says:

    There are actually two things you can do to allow correct use of destructors in virtual classes. You can either declare them as public virtual or protected non-virtual. They correspond to the cases where:
    1) You can delete the memory through the base-class pointer
    2) You can’t delete the memory through the base-class pointer

    For case 2 (a protected non-virtual destructor) you are making a statement about memory ownership that basically says ‘if you have a pointer to this base class, you don’t own the memory and therefore trying to delete it here is an error’.

    Incidentally, the exact error (resource leaks) only occurs in a situation like the following:
    class A {};
    class B : A {};
    ...
    A *ptr = new B();
    delete ptr;

    (all methods removed to make the code as succinct as possible). Basically the resource leak only occurs when you delete the derived class through a pointer to the base class (which is why a protected non-virtual destructor is fine, assuming you don’t do something insanely stupid like ‘delete this;’ ;) )

  8. elibenNo Gravatar Says:

    @David,

    I think the code sample you present (which is case 1 according to your earlier enumeration) is quite common, which is why having a virtual destructor in A is needed. Without a virtual destructor, only the A part of B will be cleaned up, which is a memory leak.

  9. David WorkmanNo Gravatar Says:

    @ellben
    Or you make the destructor protected non-virtual, which makes the ‘delete ptr;’ statement something that won’t compile :)

  10. David WorkmanNo Gravatar Says:

    Oh, also I just realised that it isn’t an automatic memory leak just from not making the destructor virtual. As an example:
    class A {
    public:
    A() {
    c = new C();
    ]
    ~A() {
    delete c;
    ]
    };

    class C {};

    class B : A{

    };
    ...
    A* ptr = new B();
    delete ptr;

    The above won’t cause a resource leak as all of the memory allocated in the ‘new’ statement is freed, but the destructor in B isn’t called, which is fine in this circumstance. However, if B looked like:
    class B : A {
    public:
    C* c_;
    B() {
    c_ = new C();
    }
    ~B() {
    delete c_;
    }
    ];

    Now we have a resource leak.

    In the situation where A is a normal subclass, you’d make the destructor virtual, as deleteing a derived class through a subclass makes sense. When A is more like an interface though and contains just pure virtual methods (potentially with several interfaces being inherited by one class) then making the interface destructor protected non-virtual makes more sense as you generally don’t want to allow someone to delete a pointer to an interface.

  11. elibenNo Gravatar Says:

    @David,

    I agree that when no extra resources are allocated in the derived objects, no leak will occur. However, as a good design practice, I would always use a virtual base destructor in a class with virtual functions that’s to serve as a base of a hierarchy.

  12. Michal MocnyNo Gravatar Says:

    There are even more complex situations where a Base can be without a virtual destructor, be used polymorphically, and yet still call the Derived destructor properly: read the most important const, guru question #3

    Just FYI, I tested this with a protected base destructor, and it still compiles, so, I can think of no example where I wouldn’t apply the two rules David outlined. Thanks for pointing that part out.

  13. elibenNo Gravatar Says:

    @Michal,

    Thanks for the link – I learned something new. Still, if I can, I will avoid code where I have to read a GoTW entry to just know it works. Having a virtual base destructor is more straightforward. Are there any important use-cases where you’d like to avoid it?

  14. rmnNo Gravatar Says:

    Pretty close to this: http://cplusplus.co.il/2009/08/22/pure-virtual-destructor/
    :)

  15. elibenNo Gravatar Says:

    @rmn,

    It is quite close, indeed. Had I seen your post, I wouldn’t have written this one for sure. As in most blog posts, I don’t claim originality. I assume this issue of pure virtual destructors is covered in at least another dozen posts/articles/discussions online.

  16. David WorkmanNo Gravatar Says:

    For complete clarity, I think it’s also worth mentioning that the subject of virtual destructors is also covered in either ‘Effective C++’ or ‘More Effective C++’ too, which I’d consider must-reads for C++ devs (although make sure you grab the 2nd edition of Effective C++, as the first edition is now quite old and not as applicable) :)

  17. ChristopherNo Gravatar Says:

    It is also worth noting that there is nothing wrong with a pure virtual function having an implementation.

Leave a Reply

To post code with preserved formatting, enclose it in `backticks` (even multiple lines)