Search code examples
c++virtual-destructor

Force virtual destructors? C++


I didn't see the answer to this in the C++ Faq lite:

How do I define a base class so every class inheriting it is required to define a destructor?

I tried running this program

struct VDtor { virtual ~VDtor()=0;  };
struct Test:VDtor { virtual ~Test(){}  };
int main() { delete new Test; return 0; }

http://codepad.org/wFcE71w3 With the error

In function `Test::~Test()':
t.cpp:(.gnu.linkonce.t._ZN4TestD0Ev+0x1e): undefined reference to `VDtor::~VDtor()'
In function `Test::~Test()':
t.cpp:(.gnu.linkonce.t._ZN4TestD1Ev+0x1e): undefined reference to `VDtor::~VDtor()'

So, is it possible?


Solution

  • It is "possible" in some sense (if your goal was that the derived class stays abstract otherwise). But it won't give the result you would like: Because the compiler will create a destructor itself implicitly if the programmer hasn't done so.

    It's therefor not possible to force the derived class' author to explicitly declare a constructor.

    (edit: Like @chubsdad notes noted, the error in your particular code is because you need to define the explicitly declared destructor of the base class).


    Edit: Just for fun, there are situations that necessiate an explicitly declared constructor. Consider the following

    struct Viral {
      struct Dose { };
    protected:
      ~Viral() throw (Dose) { }
    };
    
    struct Base {
      virtual ~Base() throw() { }
    };
    
    struct Derived : Base, Viral { };
    

    This code won't compile because the implicitly declared ~Derived will have an exception specification throw (Dose) which is looser than what ~Base has - so it violates the requirement that overriders shall not have a looser exception specification. You will need to explicitly declare the destructor appropriately

    struct Derived : Base, Viral { ~Derived() throw() { } };
    

    But this is not really a solution to your problem, because derived classes need to "cooperate" into either deriving from Viral or putting it as a non-static data member. It's also very ugly :)


    Edit: The following seems to be a Standard conforming way to do it

    struct Viral {
      struct Dose { };
    protected:
      ~Viral() throw (Dose) { }
    };
    
    struct Base : virtual Viral {
      virtual ~Base() throw() { }
    };
    

    Clang and GCC (starting with v4.6) reject any derived class of Base that has an implicitly declared destructor, because it has an incompatible exception specification (any derived class shall call ~Viral directly, instead of indirectly by calling ~Base, the Standard says). Comeau accepts this, but I strongly suspect that it is non-conforming in this regard.