Possible Duplicate:
GNU compiler warning “class has virtual functions but non-virtual destructor”
I am writing an interface for two classes and I get the warning in the title. Here's the code:
class GenericSymbolGenerator {
protected: // <== ok
~GenericSymbolGenerator(void) {}
public:
virtual GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymbolTableCollection *gst) = 0;
GenericSymbolGenerator(void) {}
// ~GenericSymbolGenerator(void) {} // <== warning if used
};
class PascalPredefinedSymbolGenerator : public GenericSymbolGenerator {
protected:
~PascalPredefinedSymbolGenerator(void) {} // <== ok
public:
GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymbolTableCollection *pst); // initializes *pst
PascalPredefinedSymbolGenerator(void) {}
// ~PascalPredefinedSymbolGenerator(void) {} <== warning if used
};
class PascalSymbolGenerator : public GenericSymbolGenerator {
protected:
~PascalSymbolGenerator(void) {} // <== ok
public:
GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymbolTableCollection *st); // initializes st
PascalSymbolGenerator(void) {}
// ~PascalSymbolGenerator(void) {} // <== warning if used
};
As long as the constructor/destructor is void there is no issue in declaring the destructor as protected. The problem arises when the class makes use of the heap(the destructor being declared as protected there is no way of freeing the class from the "outside" making the object "indestructible"). Is there a more convenient approach(aside from going public all the way)?
Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior.
In C++, the constructor cannot be virtual, because when a constructor of a class is executed there is no virtual table in the memory, means no virtual pointer defined yet. So, the constructor should always be non-virtual. But virtual destructor is possible.
Yes, it is possible to have a pure virtual destructor. Pure virtual destructors are legal in standard C++ and one of the most important things to remember is that if a class contains a pure virtual destructor, it must provide a function body for the pure virtual destructor.
While defining (providing an implementation) pure virtual methods is rarely useful, you must define a pure virtual destructor. This is because the destructor of a base class is always called when a derived object is destroyed. Failing to define it will cause a link error.
Classes for use as polymorphic bases should have either a virtual destructor or a protected destructor.
The reason is that if you have a public, non-virtual destructor, then pretty much any use of it by an external user of the class is unsafe. For example:
GenericSymbolGenerator *ptr = new PascalPredefinedSymbolGenerator();
delete ptr; // behavior is undefined, we tried to call the base class destructor
By marking the destructor protected
, you prevent the user from deleting a PascalPredefinedSymbolGenerator
object via the base class. By making the destructor public and virtual
, you get defined behavior when the user deletes through the base class. So pick one of those options.
I would argue that the compiler is correct to warn you about the non-virtual destructor in the base class. You have created a class that is clearly intended as the root of an inheritance hierarchy, but by making the base class destructor non-virtual, you've broken your ability to delete an object by pointer to the base class (as all that will be executed is the destructor of the base class, so no derived class specific actions will be taken). This is considered a really bad idea in C++ as you essentially break the implementation of polymorphism when it comes to this object hierarchy.
As you mentioned in your comments, your intent is to use GenericSymbolGenerator as an interface and force the user to instantiate and use derived classes containing the actual implementation code. The canonical way to declare an interface in C++ is to declare at least one function on the interface as a pure virtual function. This prohibits you from instantiating the base class, but still create instantiable derived classes. You've already done this by declaring generateSymbolTableCollection()
as a pure virtual function in your base class. So all you need to do is make the destructor virtual as it really has to be virtual in this particular scenario.
Also, as an aside, the canonical signatures for the default constructor and destructor are normally written without using "void" as a parameter, just use the empty parentheses instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With