以多态方式捕获异常

时间:2009-08-03 10:49:05

标签: c++ exception inheritance reference virtual

以下是main()

int main()
{
    B b(1,"two","three");
    try
    {
        f1(b);
    }
    catch(B& b_ref)
    {
        cout<<"Caught B&"<<endl;
        b_ref.print();
    }
    catch(A& a_ref)
    {
        cout<<"Caught A&"<<endl;
        a_ref.print();
    }

    system("pause");
    return 0;
}

以下是f1()

void f1(A& subject)
{
    throw subject;
}    

信息:

B继承自A. A::print()是虚拟的,并在B中重新实现。捕获异常的catch是catch(A& a_ref),我认为这是有意义的,因为异常'静态类型(主题)是A&amp ;.但是,为什么B:: print()没有运行?动态类型“丢失”了吗?只有A::print()a_ref.print();行中运行。

有人可以解释一下吗?

6 个答案:

答案 0 :(得分:6)

throw只抛出一个跟在它后面的表达式类型的对象。在这种情况下,subject的类型为A&,无论实际对象是什么,因此抛出A(请注意,不能抛出引用,因此会生成副本)。

您可以通过向引发异常的异常类添加成员函数来解决此问题。只要在每个类中实现此方法,被调用的覆盖将知道对象的运行时类型,并且可以throw *this

http://www.ddj.com/cpp/184401940

答案 1 :(得分:6)

根据C ++标准15.1 / 3:

  

throw-expression初始化一个临时对象,称为异常对象,其类型是通过从throw的操作数的静态类型中删除任何顶级cv限定符来确定的。

因此,您创建A类型的临时对象,而不是B。

答案 2 :(得分:5)

当您说“throw subject”时,将根据投掷表达式的静态类型(subject)创建新的异常对象。 subject是引用的事实与确定要抛出的对象的目的无关。新A对象是从subject构造的副本。此副本(或可能是此副本的副本)是捕获的实际对象。

答案 3 :(得分:4)

Catch块以多态方式工作,但throw不能。当你说:

void f1(A& subject)
{
    throw subject;
}

你正在抛出A,虽然传递给函数的东西是B。

答案 4 :(得分:-1)

因为您通过引用捕获对象是“切片”。

如果您真的想要多态行为,请尝试使用像pimpl习惯用法。

答案 5 :(得分:-1)

nvm,我缺乏阅读理解能力。以为他正在创建A类对象。