C++ Virtual and Protected Destructors


Example

A class designed to be inherited-from is called a Base class. Care should be taken with the special member functions of such a class.

A class designed to be used polymorphically at run-time (through a pointer to the base class) should declare the destructor virtual. This allows the derived parts of the object to be properly destroyed, even when the object is destroyed through a pointer to the base class.

class Base {
public:
    virtual ~Base() = default;

private:
    //    data members etc.
};

class Derived : public Base { //  models Is-A relationship
public:
    //    some methods

private:
    //    more data members
};

//    virtual destructor in Base ensures that derived destructors
//    are also called when the object is destroyed
std::unique_ptr<Base> base = std::make_unique<Derived>();
base = nullptr;  //    safe, doesn't leak Derived's members

If the class does not need to be polymorphic, but still needs to allow its interface to be inherited, use a non-virtual protected destructor.

class NonPolymorphicBase {
public:
    //    some methods

protected:
    ~NonPolymorphicBase() = default; //    note: non-virtual

private:
    //    etc.
};

Such a class can never be destroyed through a pointer, avoiding silent leaks due to slicing.

This technique especially applies to classes designed to be private base classes. Such a class might be used to encapsulate some common implementation details, while providing virtual methods as customisation points. This kind of class should never be used polymorphically, and a protected destructor helps to document this requirement directly in the code.

Finally, some classes may require that they are never used as a base class. In this case, the class can be marked final. A normal non-virtual public destructor is fine in this case.

class FinalClass final {  //    marked final here
public:
    ~FinalClass() = default;

private:
    //    etc.
};