16

我在 C++ Faq lite 中没有看到这个问题的答案:

如何定义一个基类,以便每个继承它的类都需要定义一个析构函数?

我试着运行这个程序

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

http://codepad.org/wFcE71w3 出现错误

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()'

那么,有可能吗?

4

4 回答 4

17

在某种意义上它是“可能的”(如果您的目标是派生类保持抽象,否则)。但它不会给出你想要的结果:因为如果程序员没有这样做,编译器将自己隐式地创建一个析构函数。

因此,不可能强制派生类的作者显式声明构造函数。

(编辑:就像@chubsdad注释一样,您的特定代码中的错误是因为您需要定义基类的显式声明的析构函数)。


编辑:只是为了好玩,有些情况需要显式声明的构造函数。考虑以下

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

struct Base {
  virtual ~Base() throw() { }
};

struct Derived : Base, Viral { };

此代码不会编译,因为隐式声明~Derived的异常规范throw (Dose)比现有的更宽松~Base- 因此它违反了覆盖器不应具有更宽松的异常规范的要求。您将需要适当地显式声明析构函数

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

但这并不是您问题的真正解决方案,因为派生类需要“合作”以派生Viral或将其作为非静态数据成员。它也很丑:)


编辑:以下似乎是符合标准的方法

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

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

Clang 和 GCC(从 v4.6 开始)拒绝任何Base具有隐式声明的析构函数的派生类,因为它具有不兼容的异常规范(标准说,任何派生类都应~Viral直接调用,而不是通过调用间接调用~Base)。Comeau 接受了这一点,但我强烈怀疑它在这方面是不合格的。

于 2010-09-13T12:51:04.623 回答
1

无论如何,每个类都有一个析构函数。在基础中声明一个虚拟析构函数可确保子级将拥有虚拟析构函数。这并不意味着编码器需要显式声明一个析构函数——无论如何,这不是一件好事。这意味着,如果声明了析构函数,它将是虚拟的。

于 2010-09-13T13:05:52.157 回答
1
struct VDtor { virtual ~VDtor()=0;  };
VDtor::~VDtor () { } // <== Implementation.
struct Test:VDtor { ~Test(){}  };
int main() { delete new Test; return 0; }

要修复错误,您必须像上面那样实际实现 VDtor::~VDtor() 。

于 2010-09-13T14:40:30.247 回答
0

当 Test 被破坏时,它将调用它的基类析构函数,它不存在。如果您没有必要的销毁逻辑,您应该将其声明为空。

于 2010-09-13T13:27:16.940 回答