0

我刚刚读到这个答案,如果你有以下代码

class Base
{
    public Base()
    {

    }
}

class One : Base
{
    string test = "text";
}

class Two : Base
{
    string test;
    public Two()
    {
        test = "text";
    }
}

对于第一类,初始化 One.test 将在调用 Base::Base 之前初始化。但是 Two.test 将在 Base::Base 被调用后被初始化。

我认为这是因为在这两种情况下

  1. 字段 <- 这包括 One.test
  2. 基数::基数()
  3. One::One() 或 Two::Two() <- 初始化 Two.test

我想我记得初始化列表就在构造函数之前。那么初始化顺序也是:

  1. 字段
  2. 基本初始化列表
  3. 基础构造函数
  4. 自己的初始化列表
  5. 自己的构造函数

而Base的领域又是从哪里来的呢?是在分配内存时首先初始化所有字段还是在当前基类的初始化列表之前初始化所有字段?

您还能想到列表中的其他步骤吗?

如果有人能给出一个很好的概述,我将不胜感激。

4

3 回答 3

2

对于第一类,初始化 One.test 将在调用 Base::Base 之前初始化。但是 Two.test 将在 Base::Base 被调用后被初始化。

不,基础在任何成员之前初始化。

在没有虚基的简化(也是最常见的)情况下,对象的初始化顺序是:基类按照它们在类声明中出现的顺序,然后是成员按照它们在声明中出现的顺序(不是初始化列表)。只有在完成之后,才进入构造函数的主体。

虚拟基础在任何其他基础之前初始化,在另一个基础中,由从第一个声明的基础到最后一个声明的基础的深度优先搜索确定。

如果Two有一个细节可能很重要,我不确定你是否知道,在进入构造函数的主体之前,成员在初始化列表中test 初始化,然后被分配。Two

于 2013-10-25T19:31:38.900 回答
2

C++ 初始化按以下顺序进行:

  1. 基类,从左到右
  2. 成员变量,按照它们的声明顺序

从第 1 步开始的基类初始化递归地采用相同的步骤。因此,在任何成员变量初始化发生之前,以及在构造函数的主体开始执行之前,所有基都已完全构造。

因此,当编译器遇到:

Two two;

首先,Two::Two开始执行,从初始化列表开始。所有基类都通过初始化列表进行初始化,即使您没有编写或忽略基类的初始化。所以,实际运行的代码看起来更像这样:

Two::Two
:
  One(),
  test()
{
  test = "text";
}

初始化列表在构造函数的主体之前执行。因此,在开始执行One的主体之前是完全构造的。Two::Two

反过来,One看起来像这样:

One::One()
: 
  Base()
{
  string test = "test";
}

并且Base是空的:

Base::Base()
{
}

所以执行时会发生什么Two two;

  1. Base被构造。
  2. One被构造
  3. 自动变量test在上下文中被构造、初始化和销毁One::One
  4. Two::test是默认初始化的
  5. Two::test被赋值为“文本”

请注意,如果编译器认为这样做是安全的,其中一些,尤其是步骤 4 和 5 可能会被编译器优化。

于 2013-10-25T19:33:01.393 回答
1

其他人已经回答了这个问题。
但是下面的 Demo 可能会有用。

#include <iostream>
class String
{
    public:
        String(char const* d)               {std::cout << "String Constructor: " << d << "\n";}
        String()                            {std::cout << "String Constructor: Default\n";}
        String(String const& rhs)           {std::cout << "String Constructor: Copy\n";}
        String& operator=(String const& rhs){std::cout << "String Assignment\n";}
        ~String()                           {std::cout << "String Destructor\n";}
};

class Base
{
    public: Base()
    {
        std::cout << "Base::Base()\n";
    }
};

class One : Base
{
    String test = "text";
};

class Two : Base
{
    String test;
    public: Two()
    {
        std::cout << "Two::Two\n";
        test = "text";
    }
};

int main()
{
    std::cout << "Trying One\n";
    One     one;

    std::cout << "==========\n\n\n";
    std::cout << "Trying Two\n";
    Two     two;

    std::cout << "==========\n\n\n";
    std::cout << "Trying Base\n";
    Base    b;
}

结果:

> ./a.out
Trying One                    // Outside the class about to start
Base::Base()                  // One: Calls the base constructor first Base
String Constructor: text      // One: Constructs its members.
==========


Trying Two                    // Outside the class about to start
Base::Base()                  // Two: Calls the base construtor first
String Constructor: Default   // Two: Constructs its members next
Two::Two                      // Two: Now entering the body of the constructor
String Constructor: text      //      Builds a string
String Assignment             //      Calls the assignment constructor.
String Destructor             //      Temporary destroyed.
==========                    //


Trying Base
Base::Base()
String Destructor             // Destroys the string in Two
String Destructor             // Destroys the string in One
于 2013-10-25T20:32:45.397 回答