2016-10-02 132 views
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调用。但显然这必须是错误的,因为编译器正在拒绝它。它似乎想我直接从IllegalArgumentException构造函数调用std::runtime_error构造函数(编译错误消失,当我这样做),但是这似乎是错误的,因为这样我会被要求std::runtime_error构造器两次:一次是在构造函数RuntimeException,并再次在IllegalArgumentException的构造函数中。

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

回答

2

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

所以,任何派生类的构造函数需要提供的参数来virtual碱,例如:

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

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

+0

谢谢你,你的解释很清楚。鉴于此,我很可能最终会从'std :: exception'派生并使用我自己的'std :: string'。这似乎是最简单的方法。 –

相关问题