为什么Base
catch
处理程序捕获Derived
对象,如:
#include <iostream>
using namespace std;
class Base {};
class Derived: public Base {};
int main()
{
Derived d;
try {
throw d;
}
catch(Base b)
{
cout << "Caught Base Exception";
}
catch(...)
{
cout << "Default\n";
}
return 0;
}
我得到的输出是&#34; Caught Base Exception&#34;。我期待&#34;默认&#34;。
答案 0 :(得分:2)
因为Derived
可以隐式转换为Base
,所以当尝试第一个catch
处理程序时,它会成功。这与我们将所有std
例外调用为:
catch (std::exception const& e) {
..
}
否则,我们必须列举所有这些 - 这在最好的情况下是乏味的,在最坏的情况下是不可能的。
答案 1 :(得分:2)
Catch子句按列出顺序进行评估。当catch子句参数满足与throw表达式对应的某些先决条件时,搜索可行的catch子句会停止:
当 compound-statement 中的任何语句抛出类型
E
的异常时,它将与每个的形式参数T
的类型进行匹配 handler-seq 中的catch-clause ,按列出catch子句的顺序。如果满足以下任何条件,则例外是匹配:
E
和T
属于同一类型(忽略T
上的顶级cv限定符)- 的左值引用
T
是对(可能是cv-qualified)E
T
是一个明确的公共基类E
- [...]
Base
是Derived
的明确基础,因此选择了第一个catch块。由于 catch-all 处理程序(catch(...)
)只能出现在catch处理程序列表的最后,因此它是catch处理程序中最不可行的候选者。
答案 2 :(得分:0)
认为是这样。
Derived* d = new Derived;
Base* b = d;
这是有效的,因为父类引用变量可以指向子类对象。从Derived
到Base
的类型会自动转换(隐式转换)。
try-catch
块中的情况相同。
你抛出一个Derived
对象(referebce)。它可以从Derived
参考或前任参考中捕获。
理想情况下,try-catch
应如下所示。
Derived d;
try {
throw d;
}
catch(Derived d)
{
cout << "Caught Derived Exception";
}
catch(Base b)
{
cout << "Caught Base Exception";
// This will catch any other references which extends Base as well.
}
catch(...)
{
cout << "Default\n";
}
return 0;
交换第1和第2个catch子句可能会导致意外行为。