c – 继承构造函数和虚拟基类

我即将创建一个异常类层次结构,概念上看起来像这样:

#include <iostream>
#include <stdexcept>

class ExceptionBase : public std::runtime_error {
public: 
    ExceptionBase( const char * msg ) : std::runtime_error(msg) {}
};

class OperationFailure : virtual public ExceptionBase {
public: 
    using ExceptionBase::ExceptionBase;
};

class FileDoesNotExistError : virtual public ExceptionBase {
public: 
    using ExceptionBase::ExceptionBase;
};

class OperationFailedBecauseFileDoesNotExistError
    : public OperationFailure, FileDoesNotExistError {
public: 
    using ExceptionBase::ExceptionBase; // does not compile
};

int main() {
    OperationFailedBecauseFileDoesNotExistError e("Hello world!\n");

    std::cout << e.what();
}

所有构造函数应该与ExceptionBase类的构造函数相同.派生的异常仅在类型上有所不同,否则没有添加的功能.上面代码中提到的最后一个异常类型也应该有这些构造函数.这是否可以使用C 11标准的继承构造函数?如果那是不可能的:还有什么选择?

(顺便说一句:在上面的代码中,类ActionFailure和FileDoesNotExistError没有用gcc 4.8编译,但是用clang 3.4编译.显然,gcc拒绝继承虚拟基础的构造函数.知道谁在这里会很有趣.两个编译器都拒绝了class OperationFailedBecauseFileDoesNotExistError,因为继承构造函数不从直接基础继承.)

最佳答案
当using声明用于继承构造函数时,它需要一个直接的基类[namespace.udecl] / 3

If such a using-declaration names a constructor, the nested-name-specifier shall name a direct base class of the class being defined; otherwise it introduces the set of declarations found by member name lookup.

即在您的情况下,OperationFailedBecauseFileDoesNotExistError中的using声明不继承,但重新声明(作为别名)或取消隐藏ExceptionBase的ctor的名称.

您必须为OperationFailedBecauseFileDoesNotExistError编写一个非继承的ctor.

顺便说一句,这适用于非虚拟基类:继承ctors的using声明被重写为:

//using ExceptionBase::ExceptionBase;

OperationFailure(char const * msg)
: ExceptionBase( static_cast<const char*&&>(msg) )
{}

由于您可能只在mem-initializer-list中初始化直接基类(或虚基类),因此非虚基类限制using-declaration仅从直接基类继承ctors是有意义的.

继承ctors提议的作者已经意识到这打破了对虚拟基类ctors的支持,参见N2540

Typically, inheriting constructor definitions for classes with virtual bases will be ill-formed, unless the virtual base supports default initialization, or the virtual base is a direct base, and named as the base forwarded-to. Likewise, all data members and other direct bases must support default initialization, or any attempt to use a inheriting constructor will be ill-formed. Note: ill-formed when used, not declared.

转载注明原文:c – 继承构造函数和虚拟基类 - 代码日志