在 C++ oop 中抛出对象与抛出变量作为异常

Sad*_*yem 1 c++ exception

我读过一本书,其中异常的面向对象实现如下:

矩形.hpp

class Rectangle
{
private:
    // code

public:
    class NegativeSize
    {
        // empty class declaration
        // for exception
    };

    // code
};
Run Code Online (Sandbox Code Playgroud)

每当发生特定错误时,都会从构造函数中抛出 NegativeSize(),如下所示:

矩形.cpp

void Rectangle::setX(int _x)
{
    if (_x < 0)
    {
        // this instantiates an object
        throw NegativeSize();
    }

    x = _x;
}
Run Code Online (Sandbox Code Playgroud)

主程序

    try
    {
        // code
    }
    catch (Rectangle::NegativeSize)
    {
        cout << "Negative value entered" << endl;
    }
Run Code Online (Sandbox Code Playgroud)

但我可以通过在 Rectangle 类中声明一个公共变量并抛出它来完成同样的事情:

矩形.hpp

class Rectangle
{
private:
    // code

public:
    string NegativeVal;

    // code
};
Run Code Online (Sandbox Code Playgroud)

矩形.cpp

void Rectangle::setX(int _x)
{
    if (_x < 0)
    {
        throw NegativeSize;
    }

    x = _x;
}
Run Code Online (Sandbox Code Playgroud)

主程序

    try
    {
        // code
    }
    catch (string NegativeSize)
    {
        cout << "Negative value entered" << endl;
    }
Run Code Online (Sandbox Code Playgroud)

第二种实现可以被认为是一个好的实践吗?

use*_*522 5

The actual exception object that the catch clause will catch is not the object that you name or refer to in the throw expression. Instead the exception object is an object of the same (decayed) type as the throw operand and initialized from the same.

因此,在第一个示例中,您抛出一个Rectangle::NegativeSize初始化类型的对象NegativeSize(),在第二个示例中,您抛出一个成员std::string的副本NegativeSize,无论它当时持有什么值。

在第二个示例中将catch (Rectangle::NegativeSize)不起作用,因为它NegativeSize不再是一种类型。相反,您将需要捕获std::string,这当然是一个问题,因为它根本没有告诉您这是什么类型的异常(以及其他一些更深层次的问题)。

因此,抛出异常类std::string而不是特定的异常类并不是一个好的做法。您将无法区分不同的异常并仅捕获您可以在给定子catch句中处理的异常。

抛出数据成员似乎也毫无意义。您将其设置为什么值?也许只是"Negative value entered"字符串?如果是的话,那也可以直接扔掉throw std::string("Negative value entered");。正如我上面所说,无论如何,异常对象都将是一个副本。在catch子句中,您无法再识别表达式是否throw使用了NegativeSize成员。

而且,在实践中,异常类通常是从它派生的std::exception,或者是从它派生的类,并且不为空。它们通常存储一个可以在表达式点给出的字符串throw,以便可以向用户提供来自异常源的详细信息,例如:

class Rectangle
{
private:
    // code

public:
    struct NegativeSize : std::invalid_argument {};

    // code
};

//...

void Rectangle::setX(int _x)
{
    if (_x < 0)
    {
        throw NegativeSize("Negative value entered");
    }

    x = _x;
}

//...

try
{
    // code
}
catch (const Rectangle::NegativeSize& e)
{
    cout << e.what() << endl;
}
Run Code Online (Sandbox Code Playgroud)

另外,正如我上面所做的那样,通常应该通过引用捕获异常。