我在程序组件中设计异常类的层次结构时遇到了麻烦。
在此组件中有几个失败案例(属于,例如std::bad_alloc
,std::invalid_argument
,std::system_error
等...),对于每个非常具体的失败案例,我做了相应的异常类,源自上述一般异常类别。
现在,我被要求将所有异常类派生自一个类,比如说Base
,这样我的客户端就可以通过简单地捕获{{1}来知道失败是否来自我的组件}。但是,我的组件的另一个客户端对异常发生的位置以及发生异常的原因不感兴趣。因此,我的异常类似乎必须从通用标准异常类以及单个可分区基类Base
派生。
我的问题是:我应该Base
来自Base
吗?
如果它是从std :: exception派生的,那么每个异常类中必须有两个std :: exception实例,因为标准异常类似乎没有使用虚拟继承。我认为在这种情况下我必须为每个异常类将转换运算符写入std::exception
,这看起来非常繁琐。
如果它不是从std :: exception派生的,那么只想抓住std::exception
的客户端就不能使用std :: exception的能力,例如Base
,除非我在基类中实现它们。如果是这种情况,所有异常类基本上都有一个单一能力的名称,这看起来很荒谬。此外,如果客户希望将其重新抛出给期望从what()
派生的异常类的其他人,则客户端必须进行某种形式的重新打包,这是非常不受欢迎的。
我该怎么办?
修改 第二个客户的要求是他/她想要使用标准的异常类而不是我所做的,因为他/她正在使用很多组件,同时抛出太多种异常,所以他/她只是不知道所有的失败案例。
答案 0 :(得分:0)
您可以 - 不必 - 来自std::exception
。如果你这样做,虚拟地继承。它会慢一点 - 但在不可避免的尝试捕获旁边并不明显。
另请注意,根据您所写的内容,您可以简单地进行多级继承:
class Base : public std::exception { ... };
class BadAlloc : public Base { ... };
class InvalidArg : public Base { ... };
编辑:
由于您要从另一个层次结构的成员继承层次结构,因此需要第二个作为模板参数。您可以使用Base / BaseImpl范例注入自定义基类:
class Base
{
public:
virtual int getTheMeaning() const = 0;
};
template<typename SecondBase = std::exception>
class BaseImpl : public Base, public SecondBase
{
public:
BaseImpl(int localMeaning) : meaning_(localMeaning * 3) {}
int getTheMeaning() const override { return meaning_; }
private:
const int meaning_;
};
class InvalidArg : public BaseImpl<std::logic_error>
{
public:
InvalidArg() : BaseImpl<std::logic_error>(14) {}
};
然后你可以抓住const std::logic_error&
或const Base&
,我相信你想要的。这样做的好处是const Base&
仍然可以在BaseImpl<>
中实现虚函数,因此显式细节可以由后者驱动。