C++中析构函数和构造函数的调用顺序是什么

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/654428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:32:16  来源:igfitidea点击:

What is the order in which the destructors and the constructors are called in C++

c++constructordestructor

提问by hozefam

What is the order in which the destructors and the constructors are called in C++? Using the examples of some Base classes and Derived Classes

在 C++ 中调用析构函数和构造函数的顺序是什么?使用一些基类和派生类的例子

回答by Brian R. Bondy

The order is:

顺序是:

  1. Base constructor
  2. Derived constructor
  3. Derived destructor
  4. Base destructor
  1. 基础构造函数
  2. 派生构造函数
  3. 派生析构函数
  4. 基础析构函数

Example:

例子:

class B
{
public:
  B()
  {  
    cout<<"Construct B"<<endl;
  }

  virtual ~B()
  {
    cout<<"Destruct B"<<endl;
  }
};

class D : public B
{
public:
  D()
  {  
    cout<<"Construct D"<<endl;
  }

  virtual ~D()
  {
    cout<<"Destruct D"<<endl;
  }
};



int main(int argc, char **argv)
{
  D d; 
  return 0;
}

Output of example:

示例的输出:

Construct B

Construct D

Destruct D

Destruct B

构造B

构造 D

破坏 D

破坏B

Multiple levels of inheritance works like a stack:

多级继承就像一个堆栈:

If you consider pushing an item onto the stack as construction, and taking it off as destruction, then you can look at multiple levels of inheritance like a stack.

如果您考虑将一个项目推入堆栈作为构造,而将其取下作为销毁,那么您可以像堆栈一样查看多个层次的继承。

This works for any number of levels.

这适用于任意数量的级别。

Example D2 derives from D derives from B.

示例 D2 派生自 D 派生自 B。

Push B on the stack, push D on the stack, push D2 on the stack. So the construction order is B, D, D2. Then to find out destruction order start popping. D2, D, B

将 B 推入堆栈,将 D 推入堆栈,将 D2 推入堆栈。所以施工顺序是B、D、D2。然后找出破坏顺序开始弹出。D2、D、B

More complicated examples:

更复杂的例子:

For more complicated examples, please see the link provided by @JaredPar

有关更复杂的示例,请参阅@JaredPar 提供的链接

回答by JaredPar

A detailed description of these events, including virtual and multiple inheritance is available at the C++ FAQ Lite. Section 25.14 and 25.15

C++ FAQ Lite 中提供了这些事件的详细描述,包括虚拟继承和多重继承。第 25.14 和 25.15 节

https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

回答by Ferruccio

Also, keep in mind that while array elements are constructed first -> last, they are destructed in the reverse order: last -> first.

另外,请记住,虽然数组元素首先构造 -> 最后,但它们以相反的顺序销毁:最后 -> 首先。

回答by Everyone

I must add to the previous answers because everyone seems to be ignoring it

我必须补充以前的答案,因为每个人似乎都忽略了它

When you have a derivedclass instance being created, it is true that the code insidethe constructor of the basewill be called beforethe code insidethe constructor of the derived, but keep in mind that the derivedis still technically "created"beforethe base.

你有一个当派生被类实例创建,它是真实的代码的的构造基地将被调用之前的代码里面的的构造函数派生,但要记住的是,得到的仍是技术上的“创造”之前基地

And when you have the derivedclass destructor being called, it is true that the code insidethe derived destructor is called beforethe code insidethe base destructor, but also keep in mind that the baseis destroyedbeforethe derived.

而当你有派生类的析构函数被调用,这是事实,代码里面派生的析构函数被调用之前的代码里面基本的析构函数,也请记住,该基地摧毁导出

When I am saying created/destroyedI am actually referring to allocated/deallocated.

当我说created/destroyed 时,我实际上指的是allocation/deallocated

If you look at the memory layout of these instances, you will see that the derived instance composesthe base instance. For example:

如果查看这些实例的内存布局,您将看到派生实例构成了基础实例。例如:

Memory of derived: 0x00001110 to 0x00001120

派生内存:0x00001110 到 0x00001120

Memory of base : 0x00001114 to 0x00001118

基址内存:0x00001114 到 0x00001118

Therefore, the derived class must be allocated BEFOREthe base in the construction. And the derived class must be deallocated AFTERthe base in the destruction.

因此,必须在构造中的基类之前分配派生类。派生类必须在销毁释放基类。

If you have the following code:

如果您有以下代码:

class Base 
{
public:
    Base()
    {
        std::cout << "\n  Base created";
    }
    virtual ~Base()
    {
        std::cout << "\n  Base destroyed";
    }
}

class Derived : public Base 
{
public:
    Derived()
    // Derived is allocated here 
    // then Base constructor is called to allocate base and prepare it
    {
        std::cout << "\n  Derived created";
    }
    ~Derived()
    {
        std::cout << "\n  Derived destroyed";
    }   
    // Base destructor is called here
    // then Derived is deallocated
}

So if you created Derived d;and had it go out of scope, then you will get the output in @Brian's answer. But the object behavior in memory is not really the in same order, it is more like this:

因此,如果您创建Derived d;并让它超出范围,那么您将在@Brian 的答案中获得输出。但是内存中的对象行为并不是真正的顺序相同,更像是这样:

Construction:

建造:

  1. Derived allocated

  2. Base allocated

  3. Base constructor called

  4. Derived constructor called

  1. 派生分配

  2. 分配的基数

  3. 调用的基本构造函数

  4. 派生构造函数调用

Destruction:

破坏:

  1. Derived destructor called

  2. Base destructor called

  3. Base deallocated

  4. Derived deallocated

  1. 派生析构函数调用

  2. 基础析构函数调用

  3. 基地解除分配

  4. 派生解除分配

回答by Thong Nguyen

This is clearly described at order-dtors-for-members. Basically, the rule is "First constructed, last destructed."

这在order-dtors-for-members 中有清楚的描述。基本上,规则是“首先构造,最后破坏”。

Constructors calling order:

构造函数调用顺序:

  1. base's constructors are called in the order of appearance after the ":"
  2. derived class member's constructors are called in the order of appearance and before class's constructor
  1. base 的构造函数按照“:”后出现的顺序调用
  2. 派生类成员的构造函数按出现的顺序在类的构造函数之前调用

Destructors are called in reversed order of called constructors.

析构函数的调用顺序与被调用的构造函数相反。

Example:

例子:

#include <iostream>

struct base0 {  base0(){printf("%s\n", __func__);};~base0(){printf("%s\n", __func__);}; };
struct base1 { base1(){printf("%s\n", __func__);}; ~base1(){printf("%s\n", __func__);};};
struct member0 { member0(){printf("%s\n", __func__);};  ~member0(){printf("%s\n", __func__);};};
struct member1 { member1(){printf("%s\n", __func__);}; ~member1(){printf("%s\n", __func__);};};
struct local0 { local0(){printf("%s\n", __func__);}; ~local0(){printf("%s\n", __func__);}; };
struct local1 { local1(){printf("%s\n", __func__);};  ~local1(){printf("%s\n", __func__);};};
struct derived: base0, base1
{
  member0 m0_;
  member1 m1_;
  derived()
  {
    printf("%s\n", __func__);
    local0 l0;
    local1 l1;
  }
  ~derived(){printf("%s\n", __func__);};
};
int main()
{
  derived d;
}

Output:

输出:

base0
base1
member0
member1
derived
local0
local1
~local1
~local0
~derived
~member1
~member0
~base1
~base0