2

This is from Effective C++ (Meyers):

Classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors

I don't understand why non-polymorphic classes should not declare virtual destructors.

Assuming I have a parent class and a child class, with no virtual functions, and I have a parent-class-pointer to a child object: if I call delete on the parent-class-pointer, it will only call the parent destructor, even though I also want to call the child destructor.

migrated from cs.stackexchange.com Jan 12 '16 at 18:32

This question came from our site for students, researchers and practitioners of computer science.

  • 3
    "if I call delete on the parent-class-pointer, it will only call the parent destructor, even though I also want to call the child destructor." - Yeah that practically is using the class polymorphically then, so given the above rule it actually should have a virtual destructor. Everything fine then. – Christian Rau Jan 12 '16 at 18:35
  • 5
    "I have a parent class and a child class, with no virtual functions, and I have a parent-class-pointer to a child object" - But why would you want that? The only thing you could do with such a thing is destroy it (or use dynamic_cast). – Sebastian Redl Jan 12 '16 at 18:36
  • @SebastianRedl Or typeid! – curiousguy Nov 22 '18 at 6:49
4

The keyword here is not designed

Classes not designed to be base classes or not designed to be used polymorphically

Virtual functions/destructors are not free: they cause performance overhead so you may not want to use them in all cases. However, deleting a derived class object using a pointer to a base class that has a non-virtual destructor results in undefined behavior:

http://www.geeksforgeeks.org/g-fact-37/

So that's the trade off between performance and safety.

4

Assuming I have a parent class and a child class, with no virtual functions, and I have a parent-class-pointer to a child object

Then you are using it polymorphically.

Though I don't see much point in doing that. Without virtual members, the subclass does not have much opportunity to affect the program behaviour compared to using just the base class.

A non-polymorphic class is one that will not be used to point to objects of derived classes. These are either classes that won't be derived (which in C++ is vast majority!) or classes that are used as base for purpose of code reuse without providing complete interface for anything (e.g. std::iterator; it is a public base class of most iterators, but it makes no sense to create a std::iterator *).

1

As a concrete example, assume something like this:

class Base
{
    ...
    int some_int;
};

class Derived: public Base
{
    ...
    vector<int> some_vec; // the presence of this field makes `Derived` 
                          // no longer trivially destructible.
};

Now if we do this (either directly as shown or indirectly through a smart pointer, e.g.):

Base* base = new Derived;
...
delete base;

... then some_vec will not be destroyed unless Base defines a virtual destructor. After all, given only a base pointer, the system lacks the information at runtime to know anything about Derived unless there's a virtual table that points to its functions, allowing a dynamic dispatch to occur to get to information/functionality specific to Derived like its specific requirements for proper destruction.

To delete an object through a base pointer is polymorphic behavior, and to do it safely and correctly without running into undefined behavior requires the base class to define a virtual destructor.

The question ultimately boils down to whether you want to delete objects through a base pointer. If you do, then define a public virtual destructor:

class BaseSafeDelete
{
public:
    // Provides safe destruction through a base pointer.
    virtual ~BaseSafeDelete() {}
};

If not, define a protected nonvirtual destructor:

class BaseNoDelete
{
protected:
    // Prevents deleting outright through a base pointer.
    /*nonvirtual*/ ~BaseNoDelete() {}
};

And most importantly, inheritance is something to be designed and decided upfront when designing a base class. It's not suitable as an afterthought to take a class which was not designed for inheritance whatsoever (lacking either a protected nonvirtual dtor or a public virtual dtor as a first sign) and attempt to extend it. For that, see the Composite Reuse Principle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy