Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 请解释析构函数调用的顺序_C++ - Fatal编程技术网

C++ 请解释析构函数调用的顺序

C++ 请解释析构函数调用的顺序,c++,C++,我不明白为什么会调用“析构函数C!”。以及相关析构函数的调用序列。我觉得这好像是一个堆栈推/弹出 进一步: 为什么它在前面调用“dx(5);”,但在后面给出相应的结果?清除对象时,首先调用派生类的析构函数,然后调用基类的析构函数。创建D实例时,将调用C的构造函数,因为D继承自它当您再次销毁D时,它将调用Ds析构函数,然后调用C析构函数。当您继承时,您将“扩展”从中继承的对象。因此,如果要构建D,则需要C。当您需要销毁D时,您将销毁C,您构建它来扩展它。派生类的构造函数和析构函数调用序列如下: D

我不明白为什么会调用“析构函数C!”。以及相关析构函数的调用序列。我觉得这好像是一个堆栈推/弹出

进一步:
为什么它在前面调用“dx(5);”,但在后面给出相应的结果?

清除对象时,首先调用派生类的析构函数,然后调用基类的析构函数。

创建
D
实例时,将调用
C
的构造函数,因为
D
继承自它
当您再次销毁
D
时,它将调用
D
s析构函数,然后调用
C
析构函数。

当您继承时,您将“扩展”从中继承的对象。因此,如果要构建
D
,则需要
C
。当您需要销毁
D
时,您将销毁
C
,您构建它来扩展它。

派生类的构造函数和析构函数调用序列如下:

Destructor D!7
Destructor C!6
Destructor D!0
Destructor C!5
由于派生类构建在基类之上:

  • 基类必须在派生类之前构造。
  • 派生类必须在基类之前销毁。
调用
C
的析构函数是因为销毁派生类的对象包括销毁其基类子对象。根据[类别dtor]第8段:

在执行析构函数体之后。。。类X调用的析构函数。。。X的直接基类的析构函数

当控制流退出一个作用域时(例如您的函数
test()
ending),本地对象将以后进先出的方式销毁:首先创建的对象将最后销毁。根据[stmt.jump]第2段:

从作用域退出时(无论如何完成),在该作用域中构建的具有自动存储持续时间(3.7.3)的对象将按其构建的相反顺序销毁

类D派生自C,当调用D构造函数时,将首先调用C构造函数,以相反的方式调用析构函数

 I feel that it seems like the stack push/pop.

当控制流离开自动对象的定义范围时,自动对象(通常称为“局部变量”)将按与其定义相反的顺序被析构函数分解。

析构函数调用序列总是从派生对象到基对象,就像弹出堆栈一样。这允许派生类清理基类分配的资源。在这种情况下,编译器知道如何构造这个序列,因为它静态地知道对象的确切类型
x
y

然而,在某些情况下,这个序列会被打破。考虑下面的代码修改:

Further: Why it calls "D x(5);" earlier but the corresponding result is given later?
它产生以下输出:

void test()
{
    C *x = new D(5);
    D *y = new D(6,7);
    delete x;
    delete y;
}
运行此命令不会为
x
调用
~D
;对于
y
,两个析构函数都被调用

这是因为您没有在基类中声明析构函数
virtual
。当析构函数不是虚拟的时,编译器不知道在对象被指向基类的指针引用的情况下它必须调用派生类的析构函数。这就是为什么您应该在必须继承并动态分配资源的类中始终使析构函数为虚拟类

进一步:为什么它调用“dx(5);”较早,但相应的结果 以后会给你吗

这些对象在堆栈上分配(而
D*d1=newd();
将在堆上分配)

给出输出的不是对
dx(5)
的调用,而是在实例超出范围时,即退出
main()
时,对析构函数
~D
的调用


因为它是堆栈内存,所以取消分配的顺序与分配的顺序相反

当构造一个D的对象时,首先调用C的构造函数,然后调用D的构造函数。
我觉得它像是堆栈推送/弹出。
为什么不应该呢?
Further: Why it calls "D x(5);" earlier but the corresponding result is given later?
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