为什么要按基数抛出派生的 class 个捕获量?

Why throw at derived class catches by base?

对于下面的代码,结果是 "EA Exception Finished",这意味着尽管我们在派生 class 中抛出它,但它被基 class 捕获了。总是吗?如果是这样,我怎样才能使派生的 class 捕获,从而出现 "EB Exception Finished"?

此外,我无法准确理解 throw EB()catch(EA&) 的含义。 catch(EA&) 是否意味着 catch 块获取 EA object 的引用?

对不起我的无知。如果你能给我推荐一本书或其他关于异常结构的参考资料,那将是很大的帮助。

class EA {};
class EB: public EA {};

void F()
{
  throw EB();  // throw at EB().
}

int main()
{
  try
  {
    F();
  }
  catch(EA&) // caught here??
  {
    std::cout<<"EA Exception";
  }
  catch(EB&) // why not me? every time?
  {
    std::cout<<"EB Exception";
  }

  std::cout<<" Finished"<<std::endl;

  return 0;
}

因为 catch 块按照您声明它们的顺序进行检查。

你先被EA&赶上了。 EB 源自 EA,因此这是一个有效的捕获,第二个捕获被忽略。

您想首先捕获最多 "specialized" 个异常。因此,如果您切换 catch 块,它应该以另一种方式工作。

catch 语句按顺序检查。 EA&匹配,所以用了。 EB& 永远无法匹配。你需要把更具体的捕获放在第一位。

  catch(EB&) // Will catch
  {
    std::cout<<"EB Exception";
  }
  catch(EA&) // and this would catch EA objects that aren't EB.
  {
    std::cout<<"EA Exception";
  }

更改 catch 块的顺序以修复该行为:

#include <iostream>

class EA {};
class EB: public EA {};

void F()
{
  throw EB();  // throw at EB().
}

int main()
{
  try
  {
    F();
  }
  catch(EB&) // why not me? every time?
  {
    std::cout<<"EB Exception";
  }
  catch(EA&) // caught here??
  {
    std::cout<<"EA Exception";
  }

  std::cout<<" Finished"<<std::endl;

  return 0;
}

编译器甚至会警告您:

main.cpp:21:3: warning: exception of type 'EB' will be caught
   catch(EB&) // why not me? every time?
   ^~~~~
main.cpp:17:3: warning:    by earlier handler for 'EA'
   catch(EA&) // caught here??
   ^~~~~

[except.handle](工作草案)中的标准所述:

The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.

你就是这么做的。确实很有趣。
反转处理程序以解决问题。

原因:

Upcasting

的派生 class 到基础。因此总是卡在第一个捕获点上。