C++ 自定义异常层次结构。来自std::exception和std::bad_alloc的可怕钻石
我自己的异常层次结构中的继承有问题 类C++ 自定义异常层次结构。来自std::exception和std::bad_alloc的可怕钻石,c++,exception,c++11,polymorphism,multiple-inheritance,C++,Exception,C++11,Polymorphism,Multiple Inheritance,我自己的异常层次结构中的继承有问题 类Exception具有非常好的功能(回溯、日志记录等),因此它是任何异常的基类。它继承自std::exception,正如我在许多网页中看到的那样。另外,我正在使用一个单元测试框架,它报告任何意外抛出的std::exception。但最后一句话,这只是为了方便 然后,我有一个新的OutOfMemoryException类,它将由一个自定义的新\u处理程序抛出。此类继承自Exception,但也继承自std::bad_alloc,以与现有代码兼容。我想这更重要
Exception
具有非常好的功能(回溯、日志记录等),因此它是任何异常的基类。它继承自std::exception
,正如我在许多网页中看到的那样。另外,我正在使用一个单元测试框架,它报告任何意外抛出的std::exception
。但最后一句话,这只是为了方便
然后,我有一个新的OutOfMemoryException
类,它将由一个自定义的新\u处理程序抛出。此类继承自Exception
,但也继承自std::bad_alloc
,以与现有代码兼容。我想这更重要,因为new
将不再抛出std::bad_alloc
这里的问题是显而易见的:由于std::bad_alloc
源于std::exception
,我有一个可怕的菱形情况
类异常:公共std::异常{};
类OutOfMemoryException:public异常,public std::bad_alloc{};
不幸的是,正如您在这里看到的,标准异常并不是虚拟继承,因此std::exception
是一个模棱两可的基类
然后:
Exception
不继承自std::Exception
或OutOfMemoryException
不继承自std::bad\u alloc
提前谢谢你,对不起,我的英语说得不是很好。这并不是说这个解决方案很好,但它可能足以满足你的需要。 假设
std::exception
定义了一个名为func1()
的函数。当然,您将从继承中的两个路径获得它,对OutOfMemoryException::func1()
的任何调用都会给您一条关于不明确基类的编译时消息
这是一个老套而不太漂亮的解决方案。覆盖std::exception
中的非虚拟函数,只需转发任一版本。Exception::func1()
或std::bad\u alloc::func1()
我确实意识到这很难看,因为您正在重写非虚拟函数。如果被重写的函数采用参数,那么您还将面临完美的转发问题。如果不小心,可能会复制不想复制的内容,等等。但它应该允许您从std::exception调用成员函数。想到的一件事是,您可以使用(以及其他错误可能导致的其他异常类,例如运行时异常
from
runtime\u error`):
这确实不是一个很好的解决方案,因为当您有一个以上的继承级别时,会丢失一些多态属性并很容易变得复杂,但它至少可以工作
在实现方面,另一个稍微复杂一些的解决方案是将整个过程重构为两个不同的继承链,并使用伪类将这两个链组合起来:
class ExceptionT {};
class OutOfMemoryT: public ExceptionT {};
class Exception: public ExceptionT, public std::exception {};
class OutOfMemory: public OutOfMemoryT, public std::bad_alloc {};
这样,您将抛出OutOfMemory
并捕获OutOfMemory
或std::bad_alloc
这两种方法都使得在处理程序中从一个异常链(
Exception/std::Exception
)转换到另一个异常链变得更加困难,但我认为这可能没有那么重要(因为std::Exception
除了作为标准之外没有提供太多功能,您可能总是更愿意捕获异常).有一种方法可以使用额外的异常功能,但不必创建另一个异常层次结构。即,您可以使用额外的位抛出标准异常:
struct MyExceptionInfo { /* your extra functionality goes here */};
template<class T>
struct Ex : T, MyExceptionInfo
{
template<class A1, class... Args>
Ex(A1&& a1, Args&&... args)
: T(std::forward<A1>(a1))
, MyExceptionInfo(std::forward<Args>(args)...)
{}
};
int main() {
try {
throw Ex<std::runtime_error>("oops");
}
catch(std::exception &e) {
if(MyExceptionInfo* my_info = dynamic_cast<MyExceptionInfo*>(&e)) {
// use MyExceptionInfo here
}
}
}
struct MyExceptionInfo{/*您的额外功能放在这里*/};
模板
结构例:T,MyExceptionInfo
{
模板
Ex(A1和A1,参数和…参数)
:T(std::forward library for inspiration.FWIW您的类不使用虚拟继承either@R.MartinhoFernandes我的类没有使用它,因为任何虚拟继承的组合都不能解决这个问题。最大的问题是当我抛出一个OutOfMemoryException
并试图捕获std::exception
,因为它是一个模棱两可的基类,向上转换不起作用,它转到catch(…)
或std::terminate
。我明白了。这是个问题。你不能让其中一个基不是基而是成员吗?然后通过包装器提供它独有的功能。当然,在你的情况下,如果你想能够捕获OutOfMemoryException
作为异常和std::bad_alloc
以及std::exception
,那么这将不起作用。但是如果您可以选择其中一个与std::exception
一起,那么您应该可以。在我的exception
类中,没有真正的必要继承std::exception
。这只是为了方便起见,因为单元测试框架正在捕获std::exception
。我想OutOfMemoryException
必须源自std::bad_alloc
,因为当我在new_handler
+1中替换它时,它可能会破坏现有代码。第一个解决方案应该足够了;它不会丢失任何多态性。OutOfMemoryException
不应该继承自Excep尽管如此,Exception
专门化根本不应该从中继承。(注意,您编写的public ExceptionBase
没有意义,因为ExceptionBase
不是一个模板)。@Potatoswatter:感谢您捕获到了
class ExceptionT {};
class OutOfMemoryT: public ExceptionT {};
class Exception: public ExceptionT, public std::exception {};
class OutOfMemory: public OutOfMemoryT, public std::bad_alloc {};
struct MyExceptionInfo { /* your extra functionality goes here */};
template<class T>
struct Ex : T, MyExceptionInfo
{
template<class A1, class... Args>
Ex(A1&& a1, Args&&... args)
: T(std::forward<A1>(a1))
, MyExceptionInfo(std::forward<Args>(args)...)
{}
};
int main() {
try {
throw Ex<std::runtime_error>("oops");
}
catch(std::exception &e) {
if(MyExceptionInfo* my_info = dynamic_cast<MyExceptionInfo*>(&e)) {
// use MyExceptionInfo here
}
}
}