4

在我的项目中,我们有一个基本异常。用于处理显示错误对话框、日志等。我正在寻找一种方法来处理该异常的所有派生类,我认为这会起作用:

try
{
  main_loop();
}
catch (const MyExceptionBase* e)
{
  handle_error(e);
}

因为每个抛出的子实例都可以由指向其父实例的指针表示。但是不,当现在抛出异常时,它是一个未处理的异常。

为什么是这样?c++ 只抛出异常作为引用吗?从而使我的 catch 块无用?但是为什么这首先会编译呢?

我能想到的唯一其他方法是:

try
{
  main_loop();
}
catch (const ExceptionA& e)
{
  handle_error(e);
}
catch (const ExceptionB& e)
{
  handle_error(e);
}
catch (const ExceptionC& e)
{
  handle_error(e);
}

这似乎有点丑陋。这样做的正确方法是什么?没有基础异常类?还是可以按照我想要的方式解决?

Ps:handle_error()做的只是利用基类函数display_message_box()并干净地关闭程序。

4

6 回答 6

16

只需混合两种方法:使用基类和使用引用。

try
{
  main_loop();
}
catch (const MyExceptionBase& e)
{
  handle_error(e);
}

BTW C++ 可以捕获指针,如果你抛出它们。但这并不可取。

于 2009-02-12T12:47:24.237 回答
15

你最好的选择是抓住基本参考。但请通过引用而不是指针来完成。例子

try
{
  main_loop();
}
catch (const MyExceptionBase& e)
{
  handle_error(e);
}

通过指针捕获异常的问题是它必须由指针抛出。这意味着它将使用 new 创建。

throw new ExceptionA();

这留下了一个相当大的问题,因为它必须在某个时候被删除,否则你有内存泄漏。谁应该负责删除此异常?通常很难做到这一点,这就是为什么大多数人通过参考来捕捉。

一般来说,在 C++ 中,您应该...

按引用捕获,按值抛出

于 2009-02-12T13:58:55.700 回答
3

只有catch( const sometype* ptr )在抛出指针时才能使用,这在 99% 的情况下是不可取的。

之所以catch( const sometype& ptr )有效是因为 r 值可以隐式转换为常量引用。

于 2009-02-12T17:49:45.787 回答
2

我很惊讶你原来的例子不起作用。以下确实有效(至少使用 g++):

class Base { public: virtual ~Base () {} };
class Derived : public Base {};

int main ()
{
  try
  {
    throw new Derived ();
  }
  catch (Base const * b)
  {
    delete b;
  }
}

我也很确定这是为了按照 15.3/3 下的项目符号工作:

处理程序的类型为 cv1 T* cv2 并且 E 是指针类型,可以通过两者中的一个或两个将其转换为处理程序的类型

您是否通过公共继承从基本异常类型继承?基类必须是可访问的基类,这将阻止您的异常被捕获。

根据此处的所有其他答案,通过引用进行投掷/捕获的优势在于您无需担心内存的所有权等问题。但是如果上面的示例不起作用 - 那么我不知道为什么引用示例将起作用。

于 2009-02-12T14:02:24.647 回答
1

这应该有效:

try {
  main_loop();
} catch (const MyExceptionBase &e) {
  handle_error(e);
}

我假设 ExceptionA/B/C 都继承自 MyExceptionBase...我认为应该可以正常工作。

PS:您可能还需要考虑从 std::exception 继承 MyExceptionBase 。

于 2009-02-12T12:47:02.020 回答
0

正如其他人所提到的,您应该捕获对基类异常的引用。

至于为什么它首先编译,与 Java 不同,对于可以抛出或捕获的类型没有任何限制。因此,您可以为任何类型放入一个 catch 块,即使它从未被抛出,您的编译器也会很高兴地编译它。既然你可以通过指针抛出,你也可以通过指针捕捉。

于 2009-02-12T16:07:15.520 回答