Derived class with non-virtual destructor

Solution 1:

Are there any circumstances in which it is legitimate for a derived class to have a non-virtual destructor?

Yes.

A non-virtual destructor signifies that a class should not be used as a base-class.

Not really; a non-virtual destructor signifies that deleting an instance of derived via a base pointer will not work. For example:

class Base {};
class Derived : public Base {};

Base* b = new Derived;
delete b; // Does not call Derived's destructor!

If you don't do delete in the above manner, then it will be fine. But if that's the case, then you would probably be using composition and not inheritance.

Will having a non-virtual destructor of a derived class act like a weak form of the Java final modifier?

No, because virtual-ness propagates to derived classes.

class Base
{
public:
    virtual ~Base() {}
    virtual void Foo() {};
};

class Derived : public Base
{
public:
    ~Derived() {}  // Will also be virtual
    void Foo() {}; // Will also be virtual
};

There isn't a built-in language mechanism in C++03 or earlier to prevent subclasses(*). Which isn't much of an issue anyway since you should always prefer composition over inheritance. That is, use inheritance when a "is-a" relationship makes more sense than a true "has-a" relationship.

(*) 'final' modifier was introduced in C++11

Solution 2:

It is perfectly valid to have an Base class with an non virtual destructor if you are never going to call delete on a Base class pointer pointing to an derived class object.

Follow Herb Sutter's Advice:

Guideline #: Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected. For the special case of the destructor only:

Guideline #: A base class destructor should be either public and virtual, or protected and nonvirtual.


Maybe your question actually is:
Does Destructor in Derived class needs to be virtual if Base class Destructor is virtual?

The answer is NO.
If Base class destructor is virtual then the Derived class destructor is implicitly virtual already, you don't need to specify it as virtual explicitly.

Solution 3:

Addresssing the latest edit:

Edit: I am especially interested in the case where the base class of the derived class has a virtual destructor.

In that case, the destructor of the derived class will be virtual, regardless of whether you add the virtual keyword or not:

struct base {
   virtual ~base() {}       // destructor is virtual
};
struct derived : base {
   ~derived() {}            // destructor is also virtual, because it is virtual in base
};

This is not limited to destructors, if at any point in a type hierarchy a function member is declared virtual, all overrides (not overloads) of that same function will be virtual, whether they are declared as so or not. The specific bit for destructors is that ~derived() overrides virtual ~base() even if the name of the member differs --that is the only specificity for destructors here.

Solution 4:

You're question isn't really clear. If the base class has a virtual destructor, the derived class will have one, regardless. There's no way to turn virtuality off, once it's been declared.

And there are certainly cases where it makes sense to derive from a class which doesn't have a virtual destructor. The reason why the base class destructor should be virtual is so that you can delete through a pointer to the base class. If the derivation is private, you don't have to worry about this, since your Derived* won't convert to a Base*. Otherwise, I've seen the recommendation that if the base class destructor isn't virtual, it should be protected; this prevents the one case of undefined behavior (deleting through a pointer to base) that could occur. In practice, however, a lot of base classes (e.g. std::iterator<>) have semantics such that it doesn't even occur to anyone to create pointers to them; much less delete through such pointers. So adding the protection may be more effort than it's worth.

Solution 5:

Depends on the purpose of your class. Sometimes it is a good practice to make your destructor protected, but not virtual - that basically says: "You shall not delete an object of derived class via a base-type pointer"