从没有默认构造函数的虚拟基派生 class

Deriving class from virtual base with no default constructor

我正在为我正在开发的 C++ 应用程序编写一个小的异常层次结构 classes,但我无法从 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 class 编译没有问题,但是 IllegalArgumentException 拒绝在 VS2015 上编译,生成错误: no default constructor exists for class "std::runtime_error" for both constructors of IllegalArgumentException .这挑战了我对 C++ 继承层次结构的理解,因为我希望这段代码可以正常编译。

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

的构造函数中

这样做安全and/or吗?如果不是,为什么编译器似乎鼓励它?我 可以 只是从 std::exception 派生并将 std::string 自己实现为成员变量,但我认为从标准 [=42= 派生会更容易] 已经实现了这一点。这是错误的做法吗?此外,我实际上从 boost:exceptionstd::runtime_error 中得出的事实是否导致了这个问题?

当使用 virtual 继承时,virtual 基础的构造函数调用是 most derived class 的责任而不是责任任何中间体 class。原因很明显:使用 virtual 继承表示期望实际上有多个派生 class 使用基 class。这些派生的 classes 中的哪一个将负责构建 virtual 基础?

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

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

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