我即将创建一个异常类层次结构,概念上看起来像这样:
#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标准的继承构造函数功能?如果那是不可能的:还有什么选择?
(顺便说一句:在上面的代码中,类OperationFailure
和FileDoesNotExistError
没有用gcc 4.8编译,而是用clang 3.4编译。显然,gcc拒绝继承虚拟基础的构造函数。它将是很有趣,知道谁在这里。两个编译器都拒绝了类OperationFailedBecauseFileDoesNotExistError
,因为继承构造函数不从直接基础继承。)
答案 0 :(得分:2)
当 using-declaration 用于继承构造函数时,它需要一个直接的基类[namespace.udecl] / 3
如果这样的 using-declaration 命名一个构造函数, nested-name-specifier 应该命名一个被定义的类的直接基类;否则它会引入由成员名称查找找到的声明集。
即。在您的情况下,OperationFailedBecauseFileDoesNotExistError
中的 using-declaration 不会继承,而是重新声明(作为别名)或取消隐藏ExceptionBase
的ctor的名称
你必须为OperationFailedBecauseFileDoesNotExistError
写一个非继承的ctor。
顺便说一句,这适用于非虚拟基类:继承ctors的using声明被重写为:
//using ExceptionBase::ExceptionBase;
OperationFailure(char const * msg)
: ExceptionBase( static_cast<const char*&&>(msg) )
{}
由于您只能初始化 mem-initializer-list 中的直接基类(或虚拟基类),因此非虚拟基类限制使用 - 是有意义的声明仅从直接基类继承ctors。
继承ctors提案的作者已经意识到这打破了对虚拟基类ctors的支持,请参阅N2540:
通常,继承具有虚拟基础的类的构造函数定义将是不正确的,除非虚拟基础支持默认初始化,或虚拟基础是直接基础,并命名为转发的基础。同样,所有数据成员和其他直接库都必须支持默认初始化,否则任何使用继承构造函数的尝试都将是错误的。注意:使用时形成不良,未声明。
答案 1 :(得分:1)
继承构造函数就像为您指定的所有构造函数引入包装函数。在您的情况下,您必须调用OperationFailure
和FileDoesNotExistError
的特定构造函数,但引入的包装器将只调用其中任何一个。
我刚检查了the latest C++11 draft(第12.9节),但它并没有明确涵盖您的案例。