1

I just added the option Wctor-dtor-privacy and -Wnon-virtual-dtor in my makefile and I got an error in one of my file saying. I usually write either a private non virtual destructor or a public virtual destructor for my base classes. But I got a warning for one of my classes which is an interface:

class TestInterface
{
public:
    virtual void Send( const std::string& sendMessage ) = 0;
    virtual std::string PopMessage() = 0;
    virtual std::string GetLatestString() = 0;
    virtual std::string::size_type GetReceivedBufferSize() const = 0;
};

warning: all member functions in class ‘TestInterface’ are private [-Wctor-dtor-privacy]
warning: ‘TestInterface’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]

I understand this warning and I would tend to write a public virtual destructor for all my interfaces which is fine. But I do not understand why lots of websites (some teaching CPP) don't bother with this e.g.. It could lead to some errors if the class is not used properly right ?

Athanase
  • 871
  • 8
  • 24
  • Best all websites teaching C++ do so poorly. I've yet to see a good online tutorial. If you want to learn C++ I strongly recommend a good book like "The C++ Primer 5th Edition" (covering C++11) – 111111 Dec 12 '13 at 14:49
  • Yes I know :), I started with books no worries: Scott Meyers books. I was just wondering if I was doing the right thing... – Athanase Dec 12 '13 at 14:51
  • well what is the point of having private pure virtual member functions? – 111111 Dec 12 '13 at 14:53
  • Sorry I forgot the `public` keyword when typing. – Athanase Dec 12 '13 at 14:54
  • Right and add a virtual dtor, do you still get the warnings? – 111111 Dec 12 '13 at 14:54
  • No I do not have the warning, but I was wondering If I was doing the right thing since lots of people don't bother with that when it comes to interfaces. – Athanase Dec 12 '13 at 14:58
  • When it comes to C++ lots of people are wrong :) – 111111 Dec 12 '13 at 15:07

3 Answers3

3

By declaring methods virtual you indicate those methods are going to be overriden by some subclass. If you don't provide a virtual destructor deleting an subclass through a pointer will lead to undefinde behaviour. See

When to use virtual destructors?.

or

http://www.parashift.com/c++-faq/virtual-dtors.html

It's probably ommited from too focus on specific aspects or usage leading to undefinded behaviour is avoided.

Community
  • 1
  • 1
Max Power
  • 178
  • 1
  • 9
2

When you call delete on a pointer, the destructor of the most-derived object (type D) need be invoked; however the compiler only knows how to invoke the destructor of the static type (B) it sees at the moment, so if those types do not match (B != D), then B need have a virtual destructor.

This has several implications:

void stack_allocated() {
    MostDerived md;       // no need for a virtual destructor,
    ...                   // the static type (MostDerived) is the actual type.
}

void dynamically_allocated() {
    Derived* d = new MostDerived;
    delete d;                     // Derived needs a virtual destructor,
                                  // because Derived != MostDerived
                                  // Bases of Derived need no virtual destructor
}

A simplification of the rule is to say:

  • only inherit from class which have virtual methods
  • as soon as a class has a virtual method, its destructor should be private, protected or virtual

which is generally what is taught (much easier to remember) even though it is sometimes too simplistic.

-Wnon-virtual-dtor matches this simplification.

Note: there is usually no penalty to making the destructor virtual if the class already has virtual methods, because current implementations use a virtual-pointer to a single static table which regroups all the methods of the class. Furthermore, the compiler may be able to devirtualize the call if it is able to predict the dynamic type in which case it does not even have a runtime cost.


There is an alternative though: I developed -Wdelete-non-virtual-dtor to warn not at the declaration site, but at the call site (delete here). As a result, it has no false positives (providing you use final to mark leaf classes), but warns later. YMMV.

Note: for example, std::shared_ptr<Derived> p = std::make_shared<MostDerived>(); is fine even without a virtual destructor because std::make_shared creates a Deleter based on the actual type created; this is also why you can do std::shared_ptr<void> p = ...; without issues.


Regarding the IBM link you provide:

  1. the discussion is focused on abstract classes thus they should the minimum amount of code that creates an abstract class. Note, for example, how the type names are meaningless, which is arguably very bad in production code!
  2. The class is perfectly usable as-is, only if someones calls delete on a A* will you run into trouble.
Matthieu M.
  • 251,718
  • 39
  • 369
  • 642
1

An interface is an construct derived from other programming languages (eg: the .NET family). In C++ there is no interface, but an abstract base class.

Having the pattern:

class Derived : public Base, public Interface, Interface, ...

where the base class has a virtual destructor and not(!) destroying through any interface, but the base class only, will make the virtual (interface) destructor obsolete.

However any C++ class has a destructor and there might be an interface IDisposable and each other interface should derive from it:

class IDisposable { public: virtual IDisposable() {}; };

Note: The destructor is not abstract!

That, however, defeats the concept of interfaces, hence:

class IDisposable { public: virtual IDisposable() = 0; };

Which makes a hand written destructor in any concrete class mandatory! (Deleting a base class without a virtual destructor, defeats it) Getting back to the .Net family and having a c++/cli class, it is implicitly an IDisposable.

I avoid interfaces (many of these are code blow)