异常处理和强制

时间:2013-02-26 20:12:16

标签: c++ exception-handling language-design coercion subtyping

try
{
    throw Derived();
}
catch (Base&)
{
    std::cout << "subtyping\n";
}

try
{
    throw "lol";
}
catch (std::string)
{
    std::cout << "coercion\n";
}

输出:

subtyping
terminate called after throwing an instance of 'char const*'

为什么异常处理对子类型有好处,但不是强制?

2 个答案:

答案 0 :(得分:18)

捕获抛出异常与将参数传递给函数完全不同。 有相似之处,但也存在细微差别。

3个主要区别是:

  • 异常总是至少复制一次(根本无法避免)
  • catch条款按照声明的顺序进行检查(不是最合适的)
  • 他们的类型转化形式较少
    • 基于继承的覆盖,
    • 从类型化指针转换为无类型指针(const void*捕获任何指针)

不允许进行任何其他类型的转化(例如intdouble,或隐含const char*string - 您的示例。

关于评论中的问题 假设存在层次结构:

class Base {}; 
class Derived: public Base {};
class Base2 {};
class Leaf: public Derived, public Base2 {};

现在,根据catch子句的顺序,将执行适当的块。

try {
    cout << "Trying ..." << endl;
    throw Leaf();

} catch (Base& b) {
    cout << "In Base&";

} catch (Base2& m) {
    cout << "In Base2&"; //unreachable due to Base&

} catch (Derived& d) {
    cout << "In Derived&";  // unreachable due to Base& and Base2&
}

如果您切换BaseBase2抓住订单,您会发现不同的行为。 如果LeafBase2私下继承,则catch Base2&无论在何处放置都会无法访问(假设我们抛出Leaf

一般来说很简单:订单很重要。

答案 1 :(得分:8)

C ++ 11标准的第15.3 / 3段定义了处理程序与某个异常对象匹配的确切条件,并且这些条件不允许用户定义的转换

  

如果

,则处理程序匹配E类型的异常对象      

- 处理程序类型为cv Tcv T&ET属于同一类型(忽略顶级cv - 限定符) ,   或

     

- 处理程序的类型为cv Tcv T&,而T是明确的E公共基类,或

     

- 处理程序的类型为cv1 T* cv2E是一种指针类型,可以转换为类型   

之一或两者的处理程序      
      
  • 标准指针转换(4.10),不涉及转换为私有或受保护的指针   或模糊的课程

  •   
  • 资格转换

  •   
     

- 处理程序是指向成员类型的指针或指针,Estd::nullptr_t

     

[...]