以下是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();
行中运行。
有人可以解释一下吗?
答案 0 :(得分:6)
throw
只抛出一个跟在它后面的表达式类型的对象。在这种情况下,subject
的类型为A&
,无论实际对象是什么,因此抛出A
(请注意,不能抛出引用,因此会生成副本)。
您可以通过向引发异常的异常类添加成员函数来解决此问题。只要在每个类中实现此方法,被调用的覆盖将知道对象的运行时类型,并且可以throw *this
。
答案 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)