Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and why should destructor in base class NOT be defined as virtual?

This example below illustrates how to prevent derived class from being copied. It's based on a base class where both the copy constructor and copy assignment operator are declared private.

class Uncopyable
{
protected:
   // allow construction and destruction of derived objects...
   Uncopyable() {}
   ~Uncopyable() {}

private:
   // but prevent copying...
   Uncopyable(const Uncopyable&);
   Uncopyable& operator=(const Uncopyable&);
};

We can use this class, combined with private inheritance, to make classes uncopyable:

class derived: private Uncopyable
{...};

Notice that the destructor in class Uncopyable is not declared as virtual.

Previously, I learned that

  • Destructors in base classes should be virtual.
  • Destructors in non-base classes should not be made virtual.

In this example, the destructor for Uncopyable is not virtual, but it is being inherited from. This seems to go against the wisdom I've learned previously.

When and why should destructor in base class NOT be defined as virtual?

like image 833
Eric Z Avatar asked Aug 10 '11 01:08

Eric Z


2 Answers

A base class destructor only needs to be virtual if you might try deallocating an object of a derived type through a pointer of the base type. Consequently, if you only inherit from the base class privately instead of publicly, as would be the case in Uncopyable, then you don't need to worry about putting in a virtual destructor, because when using private inheritance you can't get a pointer to the derived object and store it in a pointer to the base type.

Another example might be if you were to use a mixin class like this one that makes a class track the number of object allocations, where the mixin is inherited from to acquire behavior but not to be treated polymorphically:

template <typename T> class Counter {
public:
    Counter() { ++numInstances; }
    Counter(const Counter&) { ++numInstances );
    ~Counter() { --numInstances; }

    static unsigned getNumInstances() { return numInstances; }

private:
    static unsigned numInstances;
}
template <typename T> unsigned Counter<T>::numInstances = 0;

More generally, when using static polymorphism, you don't need virtual destructors because you never treat the classes polymorphically using pointers to the base type. You only use a pointer to the derived type.

There are probably a few other cases I didn't cover here, but these two (private inheritance, mixin classes, and static polymorphism) cover much of the space where virtual destructors aren't required.

like image 63
templatetypedef Avatar answered Sep 23 '22 04:09

templatetypedef


When you design the base not as interface, but as implementation detail (note the private inheritance from Uncopyable).

like image 26
Nikolai Fetissov Avatar answered Sep 21 '22 04:09

Nikolai Fetissov