请解释析构函数调用的顺序
Please explain the sequence of destructor invocations
using namespace std;
class C
{
int a;
public:
C(int aa=0) {a=aa;}
~C() {cout << "Destructor C!" << a << endl;}
};
class D: public C
{
int b;
public:
D(int aa=0, int bb=0): C(aa) {b=bb;}
~D() {cout << "Destructor D!" << b << endl;}
};
void test()
{
D x(5);
D y(6,7);
}
int main()
{
test();
}
以上是代码,下面是运行结果:
Destructor D!7
Destructor C!6
Destructor D!0
Destructor C!5
我不明白为什么会调用"析构函数C!"。以及相关析构函数的调用序列。我觉得它看起来像堆栈推送/弹出。
进一步:为什么它更早地调用">D x(5(;",但稍后给出相应的结果?
构函数调用序列总是从派生序列转到基基,就像弹出堆栈一样。这允许派生类清理基类分配的资源。在这种情况下,编译器知道如何构造此序列,因为它知道静态x
和y
对象的确切类型。
但是,在某些情况下,此序列会被打破。请考虑对代码进行以下修改:
void test()
{
C *x = new D(5);
D *y = new D(6,7);
delete x;
delete y;
}
它产生以下输出:
Destructor C!5
Destructor D!7
Destructor C!6
运行此操作不会对x
产生~D
调用;对于y
,两个析构函数都被调用。
这是因为您没有在基类中声明析构函数virtual
。当析构函数不是虚拟的时,编译器不知道在对象由指向基类的指针引用的情况下,它必须调用派生类的析构函数。这就是为什么您应该始终在必须继承的类中使析构函数成为虚拟并动态分配资源的原因。
派生类的构造函数和析构函数调用序列如下所示:
Base Class Constructor
Derived Class Constructor
Derived Class Destructor
Base Class Destructor
由于派生类建立在基类之上:
- 基类必须在派生类之前构造。
- 派生类必须在基类之前销毁。
I feel that it seems like the stack push/pop.
D类派生自C,当调用D构造函数时,C构造函数将首先调用,析构函数则以相反的方式调用。
Further: Why it calls "D x(5);" earlier but the corresponding result is given later?
当控制流离开其定义范围时,自动对象(通常称为"局部变量"(将按其定义的相反顺序销毁。
清理对象时,首先调用派生类的析构函数,然后调用基类的析构函数。
创建D
实例时,将调用C
的构造函数,因为D
继承自它。
当您再次销毁D
时,它将调用D
析构函数,然后调用C
析构函数。
当你继承时,你"扩展"你继承的对象。所以如果你想建立D
,你需要C
.当你需要摧毁D
时,你会摧毁C
,你建造它是为了能够扩展它。
>调用 C
的析构函数是因为销毁派生类的对象包括销毁其基类子对象。根据[class.dtor]第8段:
执行析构函数的主体后...X 类调用的析构函数...X 直接基类的析构函数...
当控制流退出作用域(例如函数test()
结尾(时,本地对象将以LIFO方式销毁:首先创建的对象最后销毁。根据[stmt.jump]第2段:
退出作用域时(无论如何完成(,在该作用域中构造的具有自动存储持续时间 (3.7.3( 的对象将按其构造的相反顺序销毁。
进一步:为什么它更早地调用"D x(5(;",但相应的结果 以后给的?
这些对象在堆栈上分配(而D * d1 = new D();
将在堆上分配(。
不是对D x(5)
的调用提供输出,而是对析构函数的调用~D
实例超出范围时发生,在这种情况下,在退出main()
时。
因为它是堆栈内存,所以解除分配的顺序与分配相反;
- 函数调用中参数的顺序重要吗
- x64 函数调用参数推送/移动顺序 (MSVC)
- COUT 内部函数调用的顺序
- 构造函数的初始值设定项列表中的函数调用是否按顺序排序?
- C++:cout 和函数调用之间的计算顺序
- 当指定初始化程序的顺序和字段声明不一致时,clang可以删除函数调用
- 函数调用的顺序
- 构造函数和析构函数调用的顺序
- 析构函数调用的顺序C++
- 在虚拟继承中构造函数调用的顺序是什么
- 可变模板扩展中函数调用的顺序
- 如何将 etrace 与动态库结合使用,以按时间顺序跟踪 C++ 中的函数调用
- STL 中构造函数调用的顺序
- 此代码是否依赖于函数调用顺序未定义的行为
- 强制实施函数调用的顺序
- 函数调用的顺序
- 使用继承时构造函数/析构函数调用的顺序
- 链式静态函数调用之间的参数求值顺序
- 在块程序结束时析构函数调用的顺序
- 无法理解析构函数调用顺序