2013-10-25 107 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