通过引用捕获异常

时间:2011-12-02 00:59:53

标签: c++ exception reference

this C++ tutorial中,标题为“标准异常”的部分中,有一个示例代码,它使用从STL中的标准异常类派生的类:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex; //Declares an instance of myexception outside of the main function

int main () {
  try
  {
    throw myex;
  }
  catch (exception& e) //My question is regarding this line of code
  {
    cout << e.what() << endl;
  }
  return 0;
}

该代码打印出My exception happened。但是,如果我删除&符号,它会打印出std::exception,这是当您使用标准异常类而不是派生类调用what()时会发生的情况。

网站给出了这样的解释:

  

我们已经放置了一个通过引用捕获异常对象的处理程序   (请注意&符号后的&符号),因此也可以捕获   派生自异常的类,就像我们的类的myex对象一样   myexception。

抛出myex类似于“调用catch函数,并将myex作为参数传递”?因为就是这种情况,我会想象你是按值还是通过引用抛出异常并不重要(这是&符号的权利?),因为你仍然在抛出myexception而不是{exception 1}}。由于动态绑定和多态性等原因,e.what()仍应打印My exception happened而不是std::exception

3 个答案:

答案 0 :(得分:10)

由于对象切片而发生这种情况。

如果将派生类的对象分配给基类的实例(如在通过值时使用副本c'tor的情况下),派生类的所有信息都将丢失(切片)。

例如,

class Base {
   int baseInfo;
};

class Derived : public Base
{
   int someInfo;
};

然后,如果你写这个:

Derived myDerivedInstance;

Base baseInstance = myDerivedInstance;

然后myDerivedInstance中的“someInfo”被切除baseInstance

答案 1 :(得分:3)

你可以这样想,但是(就像函数调用一样),异常通过值传递给catch处理程序。由于它是按值传递的,因此将其复制到std::exception处理程序的catch本地。它使用std::exception的复制构造函数执行此操作,在这种情况下,副本不再具有myexception所拥有的任何私有数据,也不具有派生函数。功能完全相同。这称为“对象切片”,这就是您永远不会按值存储虚拟基类型的原因,只能通过指针或引用来存储。您会看到与std::vector<std::exception>相同的行为。包含的元素将丢失所有派生数据。

答案 2 :(得分:2)

在C ++中,您可以在传递和捕获对象时使用复制语义或引用语义,复制是从C继承的默认值。当您使用复制语义时,程序只构造异常来自 myexception 的对象。由于异常对其后代一无所知,因此您将丢失 myexception 对象的特定部分。

这就是为什么在需要多态时必须始终使用引用或指针。