Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class has virtual method but non virtual destructor C++ [duplicate]

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)?

like image 496
Sebi Avatar asked Sep 30 '12 18:09

Sebi


People also ask

Which has non-virtual destructor might cause?

Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results in undefined behavior.

Can class have virtual destructor not virtual constructor?

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.

Can we have virtual destructor and pure virtual destructor?

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.

Does a pure virtual class need a 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.


2 Answers

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.

like image 97
Steve Jessop Avatar answered Sep 20 '22 19:09

Steve Jessop


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.

like image 23
Timo Geusch Avatar answered Sep 22 '22 19:09

Timo Geusch