异常对象的静态类型

2023-12-22

我从 C++ Primer(第 5 版,第 18.1.1 节)中阅读了以下内容: “当我们抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型。”所以我尝试了以下代码:

#include <iostream>

class Base{
  public:
  virtual void print(std::ostream& os){os << "Base\n";}
};

class Derived: public Base{
  public:
  void print(std::ostream& os){os << "Derived\n";}
};

int main(){
  try{
    Derived d;
    Base &b = d;
    b.print(std::cout); //line 1
    throw b;
  }
  catch(Base& c){
    c.print(std::cout); //line 2
  }
return 0;
}

这给了我以下输出:

Derived
Base

我想我明白为什么会出现这个输出:在第 1 行,我们有动态绑定。现在,当我们抛出 b 时,它是基于 b 的静态类型,这意味着 c 的静态类型和动态类型都是 Base&,因此我们在第 2 行看到结果。

但是,如果我使用指针而不是引用:

 int main(){
  try{
    Derived d;
    Base *b = &d;
    b->print(std::cout); //line 1
    throw b;
  }
  catch(Base* c){
    c->print(std::cout); //line 2
  }
return 0;
}

输出现在变成:

Derived
Derived

这似乎暗示c的静态类型是Base*,但c的动态类型是Derived*,为什么? c 的静态和动态类型不应该都是 Base* 吗?


当我们抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型

以上内容完全属实。你忘记的是,指针也是对象。当你抛出一个指针时,那是你的异常对象.

The object you should have dynamically1 allocated is still pointed to by that Base* pointer. And no slicing occurs on it, because there is no attempt to copy it. As such, dynamic dispatch via-pointer accesses a Derived object, and that object will use the overriding function.

这种“差异”就是为什么通常最好在 throw 表达式本身中构造异常对象。


1 That pointer points to a local object, you did a big no no there and got yourself a dangling pointer.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

异常对象的静态类型 的相关文章

随机推荐