从继承的异常中抛出字符串异常 class

Throw string exception from inherited exception class

我实现了继承自 std::exception 的异常 class,如下所示:

class MyException : public exception
{
public:
    MyException(string exc)
    {
        this->exc = exc;
    }

    const char * what() const throw ()
    {
        return exc.c_str();
    }

private:
    string exc;
};

现在我手动抛出 MyException 并假设在我的 code 中发生了异常,但我在 catch 部分以两种不同的方式测试了它:

  1. 正常抓取catch (const std::exception exc)

    try
    {
        throw MyException("This is an exception");
    }
        catch (const std::exception exc)
    {
        MessageBoxA(NULL, exc.what(), "", MB_OK);
    }
    
  2. 抓取参考catch (const std::exception &exc)

    try
    {
        throw MyException("This is an exception");
    }
        catch (const std::exception &exc)
    {
        MessageBoxA(NULL, exc.what(), "", MB_OK);
    }
    

第一个抛出的异常字符串是:

Unknown exception

第二个抛出的异常(在 catch 部分有 & 的异常)是:

This is an exception

为什么我在没有引用(&)的情况下正常使用 catch 时无法获得我的自定义异常 string,为什么是 OK参考?

您正在按值捕获 std::exception,您的编译器调用了 std::exception 的复制构造函数,您的数据丢失了。

两者之一;

  1. 通过引用捕获您的异常,这不会导致复制。 或
  2. 直接抓MyException

选项 2 仍然执行复制,这是多余的,所以我会选择选项 1。

这是所有多态性都有的限制,而不仅仅是例外。

当您通过引用捕获时,您捕获了对派生 class 的现有实例的引用,因此,您可以调用它们的虚拟方法。

当你按值捕获时(你永远不应该这样做,这是原因之一),你捕获了一个 std::exception 对象本身。因为 exception 不是抽象的,所以这当然会起作用。但是,您现在获得了一个类型为 std::exception 的新对象。因此,它从来没有 exc 成员,更重要的是,它没有您想要的 what 覆盖。相反,调用了 what 的原始定义,因为您从未初始化基本异常 - 打印 "Unknown exception".

您正在经历 object slicing

value 接收派生实例作为其基础 class 时会发生这种情况——在您的情况下,按值捕获 std::exception。您的派生 class' 成员在转换为基础 class.

的过程中被“切掉”

当您希望以多态方式使用参数时,通过指针或 (const) 引用接收总是更可取。要捕获 std::exception,您应该始终通过 const 引用进行捕获(我真的想不出您 不会 的场景)。