我正在为我正在开发的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
没有默认构造函数,但构造函数正在调用它的构造函数{ {1}}。但显然这必须是假的,因为编译器拒绝它。它似乎要我直接从RuntimeException
构造函数调用std::runtime_error
构造函数(编译器错误在我这样做时消失),但这似乎是错误的,因为那时我会调用{{{{{{ 1}}两次:一次在IllegalArgumentException
的构造函数中,另一次在std::runtime_error
的构造函数中。
这样做安全和/或有效吗?如果没有,为什么编译器似乎鼓励它呢?我可能只是从RuntimeException
派生并将IllegalArgumentException
我自己作为成员变量实现,但我认为从已经实现此功能的标准类派生更容易。这是错误的做法吗?此外,我实际上是从std::exception
和std::string
推导出这个问题吗?
答案 0 :(得分:2)
使用virtual
继承时,virtual
库的构造函数调用是大多数派生类的责任,而不是任何中间类的责任。原因很明显:使用virtual
继承表明存在使用基类实际存在多个派生类的期望。这些派生类中的哪一个将负责构建virtual
基础?
因此,任何派生类的构造函数都需要为virtual
基类提供一个参数,例如:
IllegalArgumentException::IllegalArgumentException(std::string const& what)
: std::runtime_error(what)
, RuntimeException(what) {
}
为了避免让中间库调用用于virtual
继承的virtual
基类的构造函数,通常会提供默认构造函数。当然,这开启了大多数派生类错误地依赖于其基础调用的正确构造函数的可能性。