8
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 ()’

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

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

4

2 回答 2

3

我假设在真实代码中~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()。)

于 2011-07-19T21:19:42.727 回答
0

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

我理解它的方式,如果 B 类有一个析构函数,它明确地没有抛出任何东西(即。

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

应该没问题。

无论如何,上次我检查从 d'tors 抛出异常是非常糟糕的做法。

希望对你有所帮助!

于 2011-06-30T18:26:51.583 回答