It is all to do with the fact that pure virtual destructors - are handled slightly differently to normal. This explains it:
From 702 Thinking in C++ www.BruceEckel.com
Pure virtual destructors
While pure virtual destructors are legal in Standard C++, there is
an added constraint when using them:
you must provide a function body for the pure virtual destructor.
This seems counterintuitive; how can a virtual function be “pure” if it needs a function body?
But if you keep in mind that constructors and destructors are
special operations it makes more sense, especially if you remember
that
all destructors in a class hierarchy are always called.
If youcould leave off the definition for a pure virtual destructor, what function body would be called during destruction?
Thus, it’s absolutely necessary that the compiler and linker enforce the existence of a function body for a pure virtual destructor.
If it’s pure, but it has to have a function body, what’s the value of it?
The only difference you’ll see between the pure and non-pure
virtual destructor is that the pure virtual destructor does cause the
base class to be abstract, so you cannot create an object of the base
class (although this would also be true if any other member
function of the base class were pure virtual).
Things are a bit confusing, however, when you inherit a class from
one that contains a pure virtual destructor. Unlike every other pure
virtual function, you are not required to provide a definition of a
pure virtual destructor in the derived class.
The fact that the following compiles and links is the proof:
1 2 3 4 5 6 7 8 9 10 11
|
//: C15:UnAbstract.cpp
// Pure virtual destructors
// seem to behave strangely
class AbstractBase {
public:
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() {}
class Derived : public AbstractBase {};
// No overriding of destructor necessary?
int main() { Derived d; } ///:~
|
Normally, a pure virtual function in a base class would cause the derived class to be abstract unless it (and all other pure virtual functions) is given a definition.
But here, this seems not to be the case.
However, remember that the compiler automatically creates a destructor definition for every class if you don’t create one.
That’s what’s happening here – the base class destructor is being quietly
overridden, and thus the definition is being provided by the
compiler and Derived is not actually abstract.
This brings up an interesting question: What is the point of a pure virtual destructor?
Unlike an ordinary pure virtual function, you must give it a function body.
In a derived class, you aren’t forced to provide a definition since the compiler synthesizes the destructor for you.
So what’s the difference between a regular virtual destructor and a pure virtual destructor?
The only distinction occurs when you have a class that only has a single pure virtual function: the destructor. In this case, the only effect of the purity of the destructor is to prevent the instantiation of the base class.
If there were any other pure virtual functions, they would prevent the instantiation of the base class, but if there are no others, then the pure virtual destructor will do it.
So, while the addition of a virtual destructor is essential, whether it’s pure or not isn’t so important.
When you run the following example, you can see that the pure
virtual function body is called after the derived class version, just
as with any other destructor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
//: C15:PureVirtualDestructors.cpp
// Pure virtual destructors
// require a function body
#include <iostream>
using namespace std;
class Pet {
public:
virtual ~Pet() = 0;
};
Pet::~Pet() {
cout << "~Pet()" << endl;
}
class Dog : public Pet {
public:
~Dog() {
cout << "~Dog()" << endl;
}
};
int main() {
Pet* p = new Dog; // Upcast
delete p; // Virtual destructor call
} ///:~
|
As a guideline, any time you have a virtual function in a class, you should immediately add a virtual destructor (even if it does nothing).
This way, you ensure against any surprises later.