6

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

#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 标准的继承构造函数功能吗?如果这是不可能的:有什么替代方案?

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

4

2 回答 2

2

使用using-declaration继承构造函数时,需要直接基类 [namespace.udecl]/3

如果这样的using 声明命名了构造函数,则嵌套名称说明符应命名正在定义的类的直接基类;否则它会引入通过成员名称查找找到的声明集。

即在您的情况下,使用声明inOperationFailedBecauseFileDoesNotExistError不会继承,而是重新声明(作为别名)或取消隐藏 ctor 的名称ExceptionBase

您必须为OperationFailedBecauseFileDoesNotExistError.


顺便说一句,这对于非虚拟基类来说很好:继承 ctor 的 using-declaration 重写为:

//using ExceptionBase::ExceptionBase;

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

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

继承 ctors 提案的作者已经意识到这会破坏对虚拟基类 ctors 的支持,请参阅N2540

通常,为具有虚拟基的类继承构造函数定义将是格式错误的,除非虚拟基支持默认初始化,或者虚拟基是直接基,并命名为转发到的基。同样,所有数据成员和其他直接基必须支持默认初始化,否则任何使用继承构造函数的尝试都将是错误的。注意:使用时格式错误,未声明。

于 2013-10-16T14:15:33.143 回答
1

继承构造函数就像为您指定的所有构造函数引入包装函数。在您的情况下,您必须调用两者的特定构造函数,OperationFailureFileDoesNotExistError引入的包装器只会调用它们中的任何一个。


我刚刚检查了最新的 C++11 草案(第 12.9 节),但它并没有真正明确地涵盖您的情况。

于 2013-10-16T10:04:01.077 回答