【问题标题】:Deriving class from virtual base with no default constructor从没有默认构造函数的虚拟基类派生类
【发布时间】:2017-02-10 17:06:53
【问题描述】:

我正在为我正在开发的 C++ 应用程序编写一个小的异常类层次结构,但我无法从 std::runtime_error 间接派生。这是与我目前所写的代码类似的代码:

class RuntimeException : public virtual boost::exception, public virtual std::runtime_error {
public:
    virtual ~RuntimeException() {}
    RuntimeException() : runtime_error("A RuntimeException occurred.") {}
    RuntimeException(const std::string& what) : runtime_error(what) {}
};

class IllegalArgumentException : public virtual RuntimeException {
public:
    IllegalArgumentException() : RuntimeException("An IllegalArgumentException occurred.") {}
    IllegalArgumentException(const std::string& what) : RuntimeException(what) {}
};

RuntimeException 类编译没有问题,但IllegalArgumentException 拒绝在 VS2015 上编译,产生错误:no default constructor exists for class "std::runtime_error" 的两个构造函数 IllegalArgumentException。这挑战了我对 C++ 继承层次结构的理解,因为我希望这段代码编译得很好。

我的理解是IllegalArgumentException应该编译,因为尽管std::runtime_error 确实没有默认构造函数,但它的构造函数被RuntimeException 的构造函数调用。但显然这一定是错误的,因为编译器拒绝它。似乎希望我直接从IllegalArgumentException 构造函数调用std::runtime_error 构造函数(当我这样做时编译器错误消失),但这似乎是错误的,因为那时我将调用std::runtime_error 的构造函数两次:一次在RuntimeException 的构造函数中,再次在IllegalArgumentException 的构造函数中。

这样做安全和/或有效吗?如果不是,为什么编译器似乎鼓励它?我可以只是从std::exception 派生并自己将std::string 实现为成员变量,但我认为从已经实现此功能的标准类派生会更容易。这是错误的做法吗?此外,我实际上是从 boost:exceptionstd::runtime_error 派生的事实导致了这个问题吗?

【问题讨论】:

    标签: c++ inheritance virtual-inheritance ctor-initializer


    【解决方案1】:

    当使用virtual 继承时,virtual 基类的构造函数调用是最派生 类的责任,而不是任何中间类的责任。原因很明显:virtual 继承的使用表明存在一个期望,即实际上有多个派生类使用基类。这些派生类中的哪一个将负责构造virtual 基类?

    因此,任何派生类的构造函数都需要为 virtual 基类提供参数,例如:

    IllegalArgumentException::IllegalArgumentException(std::string const& what)
        : std::runtime_error(what)
        , RuntimeException(what) {
    }
    

    为了避免让中间基类调用用于virtual 继承的基类的构造函数 virtual,通常会提供默认构造函数。当然,这会导致最派生类错误地依赖于其基类之一调用的正确构造函数的可能性。

    【讨论】:

    • 谢谢你,你的解释很清楚。鉴于此,我很可能最终会从std::exception 派生并使用我自己的std::string。这似乎是最简单的方法。
    猜你喜欢
    • 1970-01-01
    • 2011-09-27
    • 2021-08-22
    • 2019-04-19
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 2020-10-29
    • 1970-01-01
    相关资源
    最近更新 更多