为什么Base Class catch块捕获派生类对象?

时间:2015-04-19 14:15:31

标签: c++ exception inheritance

为什么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;。

3 个答案:

答案 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子句的顺序。如果满足以下任何条件,则例外是匹配:

     
      
  • ET属于同一类型(忽略T上的顶级cv限定符)
  •   
  • T是对(可能是cv-qualified)E
  • 的左值引用   
  • T是一个明确的公共基类E
  •   
  • [...]
  •   

BaseDerived的明确基础,因此选择了第一个catch块。由于 catch-all 处理程序(catch(...))只能出现在catch处理程序列表的最后,因此它是catch处理程序中最不可行的候选者。

答案 2 :(得分:0)

认为是这样。

Derived* d = new Derived;
Base* b = d;

这是有效的,因为父类引用变量可以指向子类对象。从DerivedBase的类型会自动转换(隐式转换)。

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子句可能会导致意外行为。