Ral*_*zky 6 c++ virtual-inheritance c++11 inheriting-constructors
我即将创建一个异常类层次结构,概念上看起来像这样:
#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();
}
Run Code Online (Sandbox Code Playgroud)
所有构造函数应该与ExceptionBase
类的构造函数相同.派生的异常仅在类型上有所不同,否则没有添加的功能.上面代码中提到的最后一个异常类型也应该有这些构造函数.这是否可以使用C++ 11标准的继承构造函数功能?如果那是不可能的:还有什么选择?
(顺便说一句:在上面的代码中的类OperationFailure
和FileDoesNotExistError
.没有用gcc 4.8编译,但铿锵3.4显然,海湾合作委员会拒绝为虚拟基础继承构造函数这将是有趣的,知道谁在这里两种编译器拒绝了类OperationFailedBecauseFileDoesNotExistError
,因为继承构造函数不从直接基础继承.)
使用using声明继承构造函数时,需要直接基类[namespace.udecl]/3
如果这样的using 声明命名了构造函数,则嵌套名称说明符应命名所定义的类的直接基类;否则它会引入通过成员名称查找找到的声明集。
也就是说,在您的情况下,using 声明OperationFailedBecauseFileDoesNotExistError
不会继承,而是重新声明(作为别名)或取消隐藏 的 ctor 的名称ExceptionBase
。
您必须为 编写一个非继承 ctor OperationFailedBecauseFileDoesNotExistError
。
顺便说一句,这对于非虚拟基类来说很好:继承 ctor 的 using 声明被重写为:
//using ExceptionBase::ExceptionBase;
OperationFailure(char const * msg)
: ExceptionBase( static_cast<const char*&&>(msg) )
{}
Run Code Online (Sandbox Code Playgroud)
由于您只能在mem-initializer-list中初始化直接基类(或虚拟基类) ,因此对于非虚拟基类来说,限制using 声明仅从直接基类继承构造函数是有意义的。
继承 ctors 提案的作者已经意识到这会破坏对虚拟基类 ctors 的支持,请参阅N2540:
通常,继承具有虚拟基的类的构造函数定义将是错误的,除非虚拟基支持默认初始化,或者虚拟基是直接基,并命名为转发到的基。同样,所有数据成员和其他直接基数必须支持默认初始化,否则任何使用继承构造函数的尝试都将是错误的。注意:使用时格式错误,未声明。