2013-10-25 108 views
0

我刚才读的this answer,如果你有下面的代码班级成员初始化的顺序是什么?

class Base 
{ 
    public Base() 
    { 

    } 
} 

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

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

一个类initializaton One.test将基地前initalized ::基地之称。但是,在调用Base :: Base之后,Two.test将被初始化。

我想这是因为在这两种情况下,它是

  1. 领域< - 这包括One.test
  2. 基地:: Base的()
  3. 一::一()或二::两个()< - 初始化Two.test

我想我记得初始化列表只是在构造函数之前。 所以是初始化命令即可:

  1. 领域
  2. 基地初始化列表
  3. 基构造
  4. 自己的初始化列表
  5. 自己的构造

哪里做基础领域进来?当分配内存时或者在当前基类的初始化列表之前,是否所有字段都是初始化的?

在列表中您还可以想到其他步骤吗?

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

+2

那么你是如何连接使用C++一个C#的答案吗? – 0x499602D2

+0

完全错过了。那么,我仍然想知道它在C++中的工作原理。 – Sarien

+0

已编写的代码在C++中无效。 – deepmax

回答

2

C++初始化发生顺序如下:

  1. 基类,由左到右
  2. 成员变量,在他们宣布

的初始化顺序来自步骤1的基类递归地执行相同的步骤。因此,在任何成员变量初始化发生之前,构造函数的主体开始执行之前,所有基类都是完全构建的。

因此,当编译器遇到:

Two two; 

首先,Two::Two开始执行时,开始与该初始化列表。即使你没有写入一个基本类或者遗漏了一个基类的初始化,所有的碱基都通过初始化列表初始化。因此,实际运行的代码看起来更像是这样的:之前执行

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

初始化列表构造的主体。因此,OneTwo::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可能会被编译器优化。

+0

@LokiAstari:哦,哎呀。我认为它看起来是这样的:'二类:公共一'和'一类:公共基地' –

+0

'一'的情况是不完全一样的答案中描述。没有局部变量'test',而是具有初始值的成员变量。编译器将其转换为:'One():Base(),test(“test”){}' –

2

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

编号基地初始化之前任何成员。

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

虚拟基础之前被初始化任何其他基地,在其他由深度优先搜索从第一个去到最后声明的基本判断。

Two的情况下,还有一个细节,可能重要的,我不知道你都知道,成员testTwo初始化列表初始化,进入构造函数体,和然后它被分配。

+0

初始化一个基础包括递归基础,初始化列表,成员和构造函数,对吗? – Sarien

+0

@Sarien:正确,完整的初始化,包括基础,成员和构造函数体。 –

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