【问题标题】:Multiple inheritance of exception classes异常类的多重继承
【发布时间】:2016-12-22 15:49:40
【问题描述】:

我在我的程序组件中设计异常类的层次结构时遇到了麻烦。 在这个组件中有几个失败案例(例如,属于std::bad_allocstd::invalid_argumentstd::system_error 等...),对于每个非常具体的失败案例,我都创建了相应的异常类,源自以上一般异常类别。

现在,我被要求将我的所有异常类都派生自一个类,比如Base,这样我的客户就可以通过简单地捕获Base 来知道故障是否来自我的组件。但是,我的组件的另一个客户对异常发生的位置不感兴趣,但对异常发生的原因不感兴趣。因此,我的异常类似乎必须同时派生自通用标准异常类以及单个可区分的基类Base

我的问题是:我应该让Base 派生自std::exception 吗?

如果它是从 std::exception 派生的,那么每个异常类内部必须有两个 std::exception 实例,因为标准异常类似乎没有使用虚拟继承。我认为在这种情况下,对于每个异常类,我都必须将转换运算符写入std::exception,这似乎很乏味。

如果它不是从 std::exception 派生的,那么只想捕获Base 的客户端不能使用 std::exception 的能力,例如,what(),除非我在基内实现它们班级。如果是这样的话,所有的异常类本质上都为一个能力有两个名称,这似乎很荒谬。此外,如果客户端希望将其重新抛出给期望从std::exception 派生的异常类的其他人,客户端必须进行某种形式的重新打包,这是非常不可取的。

我该怎么办?

编辑: 第二个客户的要求是他/她想使用标准的异常类而不是我做的,因为他/她使用的组件非常多,同时抛出了太多种类的异常,所以他/她只是无法知道所有的失败案例。

【问题讨论】:

    标签: c++ exception multiple-inheritance


    【解决方案1】:

    您可以 - 不必 - 派生自 std::exception。如果你这样做,虚拟继承。它会慢一点 - 但在不可避免的 try-catch 旁边并不明显。

    另请注意,根据您编写的内容,您可以简单地进行多级继承:

    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&amp;const Base&amp;,这就是我相信你想要的。这样做的好处是const Base&amp; 仍然可以在BaseImpl&lt;&gt; 中实现虚函数,因此显式细节可以由后者驱动。

    【讨论】:

    • 是的,我可以从std::exception 派生,但正如我在问题中所说,转换为std::exception 变得不明确,因为std::exception 有两个实例。虚拟继承无济于事,因为例如std::logic_error 不用。
    • 否 - 如果您虚拟继承,则只有一个。这被称为敢于钻石问题的解决方案。
    • @lorro 如果我正在阅读 OP,那么情况就像this,我看不出有办法让它发挥作用。
    • @lorro - 这就是重点,另一个例外是 std::logic_error (例如)并且不可编辑
    • 我认为需要真正研究的问题是,您的基类中需要什么功能?如果您的客户希望您使用 std::exception,那么为什么不使用可用的 std::exceptions 以及您希望仅继承 std::exception 的任何其他内容?
    猜你喜欢
    • 2012-07-14
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 2014-12-27
    • 2017-02-04
    相关资源
    最近更新 更多