【问题标题】:C++ constructor & destructor orderC++ 构造函数和析构函数顺序
【发布时间】:2012-04-10 23:04:07
【问题描述】:

我正在尝试有关基类和成员构造和销毁的代码,但我对构造函数和析构函数的某些顺序感到困惑, 这段代码的输出是:

Base1 constructor
Member1 constructor
Member2 constructor
Derived1 constructor
Member3 constructor
Member4 constructor
Derived2 constructor
Derived2 destructor
Member4 destructor
Member3 destructor
Derived1 destructor
Member2 destructor
Member1 destructor
Base1 destructor

见前四行, 但我倒下的顺序应该是

Base1 constructor
Derived1 constructor
Member1 constructor
Member2 constructor

谁能给我解释一下?

#include "stdafx.h"
#include <fstream>
using namespace std;
ofstream out("order.out");

#define CLASS(ID) class ID { \
public: \
  ID(int) { out << #ID " constructor\n"; } \
  ~ID() { out << #ID " destructor\n"; } \
};

CLASS(Base1);
CLASS(Member1);
CLASS(Member2);
CLASS(Member3);
CLASS(Member4);

class Derived1 : public Base1 {
  Member1 m1;
  Member2 m2;
public:
  Derived1(int) : m2(1), m1(2), Base1(3) {
    out << "Derived1 constructor\n";
  }
  ~Derived1() {
    out << "Derived1 destructor\n";
  }
};

class Derived2 : public Derived1 {
  Member3 m3;
  Member4 m4;
public:
  Derived2() : m3(1), Derived1(2), m4(3) {
    out << "Derived2 constructor\n";
  }
  ~Derived2() {
    out << "Derived2 destructor\n";
  }
};

int main() {
  Derived2 d2;
} ///:~

【问题讨论】:

  • +1 用于提供重现问题的完整最小代码示例。

标签: c++ constructor destructor


【解决方案1】:

在初始化列表中完成的初始化发生在 Derived1 构造函数的主体之前,因此您首先会看到 m1 和 m2 的输出。

作为一个更完整的答案,发生的情况是:首先构造基子对象,然后按照它们在类中的声明顺序(而不是它们在初始化列表中的顺序)构造成员,然后执行构造函数主体.破坏以相反的顺序发生。

在这种情况下,当您构造 Derived2 时,它首先会构造 Derived1 子对象。这反过来又涉及首先构造 Base 子对象,因此它首先执行此操作。然后它构造 Derived1 的成员,执行 Derived1 构造函数的主体,构造 Derived2 的成员,最后执行 Derived2 构造函数的主体。因此观察到的输出。

【讨论】:

    【解决方案2】:

    在层次结构中向上调用构造函数:

    - base class member objects
    - base class constructor body
    - derived class member objects
    - derived class constructor body
    

    输出是正确的。

    让我们简化您的代码:

    struct BaseMember
    {
       BaseMember() { cout << "base member" <<endl; }
    };
    struct Base
    {
       BaseMember b;
       Base() { cout << "base" << endl; }
    };
    struct DerivedMember
    {
       DerivedMember() { cout << "derived member" << endl; }
    };
    struct Derived : public Base
    {
       DerivedMember d;
       Derived() { cout << "derived" << endl; }
    };
    
    Derived d;
    

    d 创建时,会先创建Base 部分。在它进入构造函数体之前,所有的成员对象都被初始化。所以BaseMember是第一个初始化的对象。

    接下来进入Base的构造函数。

    之前Derived的构造函数进入,Derived的成员对象被初始化,所以DerivedMember被创建,接下来Derived的构造函数被调用。

    这是因为当你进入派生类的构造函数体时,基类和成员对象必须完全初始化。

    EDIT 正如 Matthieu 所指出的,成员对象的初始化顺序是由它们在类定义中出现的顺序指定的,而不是它们在初始化列表中出现的顺序.

    【讨论】:

    • 注 1:对于virtual 基地,事情变得有点奇怪。注意 2:基类和属性的列出顺序无关紧要,这完全取决于它们在类定义中出现的顺序。
    • @MatthieuM。你是什​​么意思列出?
    • @MatthieuM。哦,你的意思是初始化列表?是的,确实如此。
    • @LuchianGrigore:是的,初始化列表。初学者认为它有任何影响是一个典型的错误。
    • @user1279988 这位绅士值得回答。到目前为止,许多回答了您问题的人也是如此。
    【解决方案3】:

    这仅仅是因为m1m2Derived1 构造函数的初始化列表中被初始化。初始化列表中的所有内容都是在进入构造函数的主体之前构造的。

    【讨论】:

      【解决方案4】:

      类的构造函数比其字段的构造函数执行得晚。基类及其所有成员的构造函数比派生类及其成员的构造函数执行得更早。

      【讨论】:

        【解决方案5】:

        考虑下面的程序,它会让你的想法变得清晰!

        #include<iostream.h>
        class A
        {
        public:
          A()
            {
            cout<<"\nI am the base class constructor!";
            }
          ~A()
            {
            cout<<"\nI am the base class destructor!";
            }
        };
        
        class B : public A
        {
        public:
          B()
            {
            cout<<"\nI am the derived class constructor!";
            }
          ~B()
            {
            cout<<"\nI am the derived class destructor!";
            }
        };
        
        int main()
          {
          B obj;
          return 0;
          }
        

        上述程序的输出将如下..

        我是基类构造函数!

        我是派生类的构造函数!

        我是派生类的析构函数!

        我是基类析构函数!

        我认为这解释并澄清了您对构造函数和析构函数调用顺序的查询。

        【讨论】:

          猜你喜欢
          • 2016-03-18
          • 2013-06-24
          • 1970-01-01
          • 2011-04-03
          • 2010-12-16
          • 2010-10-13
          • 2011-01-16
          • 1970-01-01
          相关资源
          最近更新 更多