无法通过引用std::exception捕获派生自std::exception的类

8
我创建了一个从std::exception派生的自定义异常类。
#include <iostream>

class Exception : std::exception {
public:
    const char* what() const noexcept override {
        return "test";
    }
};

int main() {
    try {
        throw Exception();
    } catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}   

这个程序在Ubuntu上使用"g++ -stdc++=17"编译时,即使通过引用捕获,也无法将异常捕获到catch块中。它调用了std::terminate,尽管它发生在一个通过引用捕获其基类的try块中。如果Exception从std::runtime_error继承,并在自己的构造函数中将"test"传递给std::runtime_error的构造函数,情况也是一样的。通常的解决方法是只使用Exception进行捕获,但在我的原始代码中,我需要捕获不同类型的异常,它们都继承自std::exception。为什么会发生这种情况?通过引用捕获基类不起作用吗?如何使用一个catch块捕获所有派生自std::exception的异常?
2个回答

10
当您在定义类时从基类继承时,默认的访问修饰符为 private。这意味着以下两个定义是等效的:
class derived : base { /* ... */ };
class derived : private base { /* ... */ };

这种语言不允许您从一个私有基类中引用派生类1。例如,以下代码无法编译:

int main()
{
    derived d;
    base& b = d; // <== compilation error
}
error: 'base' is an inaccessible base of 'derived'
     base& b = d;
               ^

live example on wandbox.org

这就是你的catch块无法处理Exception的原因。将继承改为public...
class Exception : public std::exception

...然后你的原始代码将会运行。

wandbox.org上的实时示例


1 参见[dcl.init.ref][conv.ptr]

2 除非你在derived本身的作用域内。请参阅wandbox.org上的实时示例


也可以从derivedfriend中捕获一个作为std::exceptionException - Peter
@Peter 在友元中是可能的,但在派生类中不行。继承至少需要被声明为 protected 才可以实现这一点。 - eerorika
好的回答 +10。谢谢。 - Joma

4

1
最好解释一下为什么私有继承无法实现此功能。 - Vittorio Romeo

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