user34537
user34537

Reputation:

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?

Upvotes: 16

Views: 2370

Answers (4)

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506925

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.

Upvotes: 17

wilx
wilx

Reputation: 18228

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

To fix the error you have to actually implement the VDtor::~VDtor() like above.

Upvotes: 1

Puppy
Puppy

Reputation: 146910

When Test is destructed, it will call it's base class destructor, which doesn't exist. You should just declare it empty if you have no necessary destruction logic.

Upvotes: 0

Steven Sudit
Steven Sudit

Reputation: 19620

Every class has a destructor, regardless. Declaring a virtual destructor in the base ensures that children will have virtual destructors. This doesn't mean that the coder will need to explicitly declare a destructor -- that wouldn't be a good thing, anyhow. All it means is that, if a destructor is declared, it will be virtual.

Upvotes: 1

Related Questions