1

我正在为我正在开发的 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。但显然这一定是错误的,因为编译器拒绝它。似乎希望我std::runtime_error直接从IllegalArgumentException构造函数调用构造函数(当我这样做时编译器错误消失了),但这似乎是错误的,因为那样我会调用构造函数std::runtime_error两次:一次在构造函数中RuntimeException,然后再次在的构造函数IllegalArgumentException

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

4

1 回答 1

3

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

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

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

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

于 2016-10-02T18:15:34.387 回答