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*'
为什么异常处理对子类型有好处,但不是强制?
答案 0 :(得分:18)
捕获抛出异常与将参数传递给函数完全不同。 有相似之处,但也存在细微差别。
3个主要区别是:
catch
条款按照声明的顺序进行检查(不是最合适的)const void*
捕获任何指针)不允许进行任何其他类型的转化(例如int
至double
,或隐含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&
}
如果您切换Base
和Base2
抓住订单,您会发现不同的行为。
如果Leaf
从Base2
私下继承,则catch Base2&
无论在何处放置都会无法访问(假设我们抛出Leaf
)
一般来说很简单:订单很重要。
答案 1 :(得分:8)
C ++ 11标准的第15.3 / 3段定义了处理程序与某个异常对象匹配的确切条件,并且这些条件不允许用户定义的转换:
如果
,则处理程序匹配E
类型的异常对象- 处理程序类型为
cv T
或cv T&
且E
和T
属于同一类型(忽略顶级cv
- 限定符) , 或- 处理程序的类型为
cv T
或cv T&
,而T
是明确的E
公共基类,或- 处理程序的类型为
之一或两者的处理程序cv1 T* cv2
,E
是一种指针类型,可以转换为类型
标准指针转换(4.10),不涉及转换为私有或受保护的指针 或模糊的课程
资格转换
- 处理程序是指向成员类型的指针或指针,
E
是std::nullptr_t
。[...]