异常对象的静态类型
Static type of the exception object
我从C++入门(第 5 版,第 18.1.1 节)中阅读了以下内容:"当我们抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型。所以我尝试了以下代码:
#include <iostream>
class Base{
public:
virtual void print(std::ostream& os){os << "Basen";}
};
class Derived: public Base{
public:
void print(std::ostream& os){os << "Derivedn";}
};
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的动态类型是派生*,为什么?c的静态和动态类型不应该都是Base*吗?
当我们抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型
以上是完全正确的。你忘记了,指针也是对象。当你抛出一个指针时,这就是你的异常对象。
您应该动态分配1 的对象仍由该Base*
指针指向。并且不会对其进行切片,因为没有尝试复制它。因此,通过指针进行动态调度访问Derived
对象,该对象将使用重写函数。
这种"差异"就是为什么通常最好在抛出表达式本身中构造异常对象的原因。
1 那个指针指向一个本地对象,你在那里做了一个很大的不,并给自己一个悬空的指针。
在第一种情况下,您正在抛出Base
类调用复制构造函数的新实例,因为您将对Base
的引用传递到运算符throw
。
在第二种情况下,您将抛出一个指向类型为 Derived
的堆栈分配对象的指针,该对象在引发异常时超出范围,因此您捕获然后取消引用导致未定义行为的悬空指针。
第一个场景
我认为,如果你在课堂上添加一些印刷品,你可以看到更清晰的画面:
struct Base {
Base() { std::cout << "Base c'torn"; }
Base(const Base &) { std::cout << "Base copy c'torn"; }
virtual void print(std::ostream& os) { std::cout << "Base printn"; }
};
struct Derived: public Base {
Derived() { std::cout << "Derived c'torn"; }
Derived(const Derived &) { std::cout << "Derived copy c'torn"; }
virtual void print(std::ostream& os) { std::cout << "Derived printn"; }
};
输出为:
Base c'tor
Derived c'tor
Derived print
throwing // Printed right before `throw b;` in main()
Base copy c'tor
Base print
如您所见,在调用throw b;
时,异常存在不同的临时Base
对象的副本构造。从 cppreference.com:
首先,从表达式复制初始化异常对象
此复制初始化对对象进行切片,就像您分配了Base c = b
第二种情况
首先,您正在抛出指向本地对象的指针,导致未定义的行为,请一定避免这种情况!
假设您修复了这个问题,并且抛出了一个动态分配的指针,它就可以工作,因为您抛出了一个指针,这不会影响对象并保留动态类型信息。
- 非类类型表达式的静态类型与动态类型之间的差异
- (2 问题)"类"类型重新定义(即使 #pragma 一次),以及静态函数内的静态成员对象初始化?
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 初始化与类类型相同的静态成员(静态初始化顺序问题)
- 我可以从静态基方法获取当前类类型 ID 吗?
- 模板静态功能模板类类型扣除
- 获取静态类功能的类类型
- 静态类模板成员:将"sizeof"应用于不完整类型无效
- 类类型的静态constexpr字段在g++中给出链接时间错误
- 如何创建一个编译时静态类类型,该类型初始化具有特定值的成员容器
- 访问.CPP中定义的某些静态变量,而其类类型也在.cpp中定义
- 通过显式转换函数初始化枚举类类型的静态constexpr类成员
- 为什么类类型的静态变量和全局变量是危险的
- 与正在定义的类类型相同的静态 constexpr 成员
- 当类类型未知时,指向非静态成员函数的函数指针
- 使用静态强制转换时,强制转换为类类型或对象引用是否更有意义
- 初始化 C++ 中类中的非基元静态数据类型
- C++静态匿名类类型数据成员
- 使用派生类类型初始化模板类的静态数组
- 为什么静态类类型函数返回零