C++中的Looser throw specifier错误

10

以下代码会生成"Looser throw specifier error"错误。你能帮我解决这个错误吗?

class base
{
    virtual void abc() throw (exp1);
}

void base::abc() throw (exp1)
{
    ......
}

class sub : public base
{
    void abc() throw(exp1, exp2);
}

void sub::abc() throw (exp1, exp2)
{
    .....
}
3个回答

13
问题的出现是因为子类必须在可以使用基类的任何地方使用,因此不能引发除基类中指定的异常类型之外的任何异常类型。
有三种解决方案:
1. 修改基类说明符,以包括任何子类可能需要抛出的每种异常类型。 2. 修改每个子类以处理除基类中指定的异常类型之外的所有异常类型。 3. 删除异常说明符。
我建议删除它们;它们被广泛认为是一个坏主意,部分原因是像这样的问题。正如Matthieu所指出的,标准委员会同意,异常说明符将在下一个标准版本中被弃用。

5
事实上,在新标准中,它们已经被“noexcept”所取代,并且被弃用:要么使用“noexcept”来表示不会抛出任何异常(相当于“throw()”,但在违反契约的情况下没有运行时诊断),要么根本不使用任何说明符,这意味着该方法可能会抛出任何异常。 - Matthieu M.
1
@Matthieu:“但是如果违反合同,没有运行时诊断” - 我以为它会终止(15.4/9),自从n3225以来有改变吗? - Steve Jessop

6
当您在派生类中使用throw specifier覆盖虚拟方法时,派生类中的方法不能抛出比超类中的方法更多的异常。如果允许这样做,您可能会通过在子类中覆盖方法来破坏超类公共API创建的契约。
在您的示例中,您说base :: abc只能抛出exp1。然而,如果您有一个指向sub实例的base类型指针,那么abc除了exp1之外还可以抛出exp2。
要解决问题,您需要从子类的throw specifier中删除exp2,或将exp2添加到超类的throw specifier中。

3
假设我尝试:
base *b = new sub;
b->abc();

根据 base::abc 中的抛出说明符,我期望它只会抛出 exp1;但是 sub::abc 表明它可能还会抛出 exp2

如果 sub::abc 真的会抛出 exp2,那么请将其添加到 base::abc 可能抛出的列表中。如果不是,则将其从 sub::abc 的列表中删除。

更好的做法是:不要使用抛出说明符。有关更多信息,请参见 Can anyone explain C++ exception specifications to me?http://www.gotw.ca/publications/mill22.htm


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接