默认析构函数的gccexception说明

class A { public: virtual ~A() { } }; class B : virtual public A { public: ~B() throw() {} }; class C : public B { }; int main(int argc, char * argv []) { return 0; } 

该代码给出了以下错误:

 error: looser throw specifier for 'virtual C::~C()' error: overriding 'virtual B::~B() throw ()' 

在我的debiantesting(gcc(Debian 4.6.0-10)4.6.1 20110526(prerelease)),但在以前的gcc版本(我的debian系统4.5再次)编译没有错误。

exception说明如何影响虚拟析构函数覆盖? 根据这个答案,编译器应该创build一个匹配基类的throw声明的默认构造函数。 显然这不是在新的gcc上发生的。 什么改变了,什么是正确的编译器行为,除了在派生类中手动添加空的析构函数(例如编译器标志)之外,还有一些简单的解决scheme。

Solutions Collecting From Web of "默认析构函数的gccexception说明"

我认为在真实代码中, ~A()~B()被声明为虚拟的? (错误信息是抱怨虚拟析构函数,但是在编写的代码中没有任何析构函数是虚拟的。)

我相信虚拟继承是触发你的问题。 C的(隐式定义的)析构函数需要先调用~B() ,然后,因为C是派生最多的类,所以调用~A() 。 (12.4 / 6)

~C()生成的异常规范需要允许任何异常传播,因为它直接调用没有异常规范的~A() 。 (15.4 / 13)

然后,这触发了你的错误 – 你不能用一个throw()规范(B的析构函数)来重载一个虚函数,而这个虚函数可能会抛出一个版本。 (15.4 / 3)

解决的办法是将throw()放在A的析构函数中。 (如果你不能这样做,那么你为什么要在B上做?)

如果没有虚拟继承,错误也不会发生 – 因为那么C的析构函数只会调用B的析构函数。 (B的析构函数仍然会调用A的 – 而且你仍然在薄冰上滑行,因为如果A的析构函数抛出你直接去terminate() 。)

GCC 4.X比以前的版本更为严格,因此可能不会隐式声明。 尝试明确说明。

我的理解是,如果B类有一个明确抛出什么的析构函数(即。

 class B: public A { public: virtual ~B() throw { } } 

应该没问题。

无论如何,上次我检查这是非常糟糕的做法,抛出了例外。

希望能帮助你一些!