异常处理+多态,如果异常方法不起作用,则在同一个类中不起作用

时间:2012-02-23 00:46:20

标签: c++ exception polymorphism virtual-functions throw

我正在尝试这样的代码

//A.hpp
 class A{
   public:
       A() {} 
       virtual const char *message() const {return "A ERROR";}
 };

 //B.hpp

 #include "A.hpp"

 class B:public A {
   public:
       B() {}
       const char *message() const {return "B ERROR";}
 };

//main.cpp
 #include "A.hpp"
 #include "B.hpp"

void foo(const A& a) {
   /* case 1 */ throw a;   /* (or) */ /* case 2 */ throw B(); // LINE 100
}

int main() {

  B b;
  A &a(b);
  b.message(); // OUTPUT: B ERROR

  try {
      foo(a);
  } catch (const A& a) {
     std::cout<<"EXCEPTION CALLED "<<a.message()<<std::endl;
  }
  return 0;
}

在这种情况下,如果我使用 情况1:       投掷// a是B b的引用;       输出:错误

案例2:      抛出B(); //创建新的B;      输出:B错误

我不明白的是,为什么两个案例之间没有一致性,

如果你一直通过引用,应该有一些一致性, 如果我在函数内部创建一个新变量,在try块中调用,那么它调用正确的虚拟方法,否则它不会.....任何人都可以告诉我控制流程....请指教。 ...

4 个答案:

答案 0 :(得分:5)

因为在抛出之前复制了一个对象。

即使a的参数foo在运行时指向B的实例,重要的是编译时类型的扔表达。因此,有效地,B的实例将传递给A的复制构造函数(自B继承A后这是合法的)和新的A实例创建然后抛出。

复制的原因是编译器必须保证异常对象的生命周期,只要有任何catch块可以捕获它。因此,它不会冒着堆栈对象“从堆栈边缘掉下来”的风险,或者堆栈对象被堆栈展开期间调用的一些析构函数释放。

答案 1 :(得分:2)

为了完整起见,我觉得有必要指出,就像虚拟副本(也称为克隆)解决了通过基础复制一样,虚拟(重新)投掷解决了通过基础投掷:

struct base {
    virtual void
    rethrow() const
    { throw *this; }

    // it's also usual to make the base type abstract
    // so that users can't slice, e.g. boost::exception
    // it's also possible to make copying protected
};

struct derived: base {
    void
    rethrow() const override
    { throw *this; }
};

void
foo(base const& b)
{
    // no: slices
    // throw b;

    b.rethrow(); // Ok
}

答案 2 :(得分:1)

投掷复制变量。你的throw a foo实际上没有从main引用a,它实际上会抛出a的副本。在catch语句中,您通过引用捕获该副本。因为在foo中,a是对A的引用,所以副本会对对象进行切片,并且它变为A,从而失去了它B的事实。

答案 3 :(得分:-1)

我很难理解你究竟在问什么,但...... 首先,不要将catch的变量命名为与本地变量相同的名称,即您使用“a”两次来表示不同的东西。您可能认为通过引用捕获的项目是您传入foo的项目,如果foo()抛出B则不会是真的。为了清楚起见,将您的捕获更改为

catch (const A& ex)
{
 ...ex.message()...
}

我怀疑发生的事情是,在尝试之外宣布时, a 仍在范围内, a.message()调用本地变量 a < / strong>即可。如果在try中声明, a 不再在catch中的范围内,那么您通过引用捕获的 a 会调用其消息。更改catch的变量名称应该可以消除看似模棱两可的行为。