2009-05-29 77 views

回答

202

對於POD班級成員,它沒有區別,這只是一個風格問題。對於類成員來說,它避免了對默認構造函數的不必要的調用。試想一下:

class A 
{ 
public: 
    A() { x = 0; } 
    A(int x_) { x = x_; } 
    int x; 
}; 

class B 
{ 
public: 
    B() 
    { 
     a.x = 3; 
    } 
private: 
    A a; 
}; 

在這種情況下,B構造函數將調用默認的構造函數爲A,然後初始化a.x到3.更好的辦法將是B的構造函數直接調用A的構造函數初始化列表:

B() 
    : a(3) 
{ 
} 

這隻會叫AA(int)構造函數,而不是它的默認構造函數。在這個例子中,差異是可以忽略的,但想象一下,如果你想讓A的默認構造函數做的更多,例如分配內存或打開文件。你不希望這樣做不必要。

此外,如果一個類沒有默認構造函數,或者你有一個const成員變量,你必須使用初始化值列表:

class A 
{ 
public: 
    A(int x_) { x = x_; } 
    int x; 
} 

class B 
{ 
public: 
    B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list; 
    {     // it is an error not to do so 
    } 
private: 
    A a; 
    const int y; 
}; 
+0

類成員這是類可以POD,太 – 2013-03-21 15:24:01

+1

一絕,也是一個參考 – 4pie0 2014-05-06 12:38:52

+1

重要的情況下,爲什麼不使用「A(3);」或「a = A(3);」在B的默認構造函數體中? – Sergey 2015-03-06 10:07:49

34
從上述性能的原因

除此之外,如果你的類存儲對作爲構造函數參數傳遞的對象的引用,或者你的類有const變量,那麼你除了使用初始值設定項列表外沒有其他選擇。

6

除了性能問題,還有一個非常重要的問題,我稱之爲代碼可維護性和可擴展性。

如果T是POD,並且您開始更喜歡初始化列表,那麼如果一次T將更改爲非POD類型,則不需要在初始化期間更改任何內容以避免不必要的構造函數調用,因爲它已經過優化。

如果類型T確實有默認構造函數和一個或多個用戶定義的構造函數,並且您決定刪除或隱藏默認構造函數,那麼如果使用初始化列表,則不需要更新代碼,如果您的用戶 - 定義的構造函數,因爲它們已經被正確地實現。

同樣的,const的成員或引用成員,假設如下初始T被定義爲:

struct T 
{ 
    T() { a = 5; } 
private: 
    int a; 
}; 

接下來,你決定來限定爲const,如果你想使用初始化列表從一開始,那麼這是一個單行的變化,但具有T標準同上,也需要挖掘構造函數定義刪除任務:

struct T 
{ 
    T() : a(5) {} // 2. that requires changes here too 
private: 
    const int a; // 1. one line change 
}; 

這不是一個祕密,維護更容易和更不容易出錯,如果代碼是不是由一個「代碼monke寫的y「,而是由一位工程師根據對他正在做的事情的深入考慮作出決定。

4

在構造函數的主體運行之前,調用其父類的所有構造函數,然後調用它的字段。默認情況下,調用無參數構造函數。初始化列表允許您選擇調用哪個構造函數以及構造函數接收哪些參數。

如果您有一個引用或常量字段,或者所用的某個類沒有默認構造函數,則必須使用初始化列表。

2
// Without Initializer List 
class MyClass { 
    Type variable; 
public: 
    MyClass(Type a) { // Assume that Type is an already 
        // declared class and it has appropriate 
        // constructors and operators 
     variable = a; 
    } 
}; 

這裏編譯器符合以下步驟創建類型的對象MyClass的
1.鍵入的構造首先被調用爲「A」。
2.「類型」的賦值運算符被稱爲內部MyClass的()構造的主體分配

variable = a; 
  • 然後終於的「類型」析構函數被稱爲爲「a」,因爲它超出了範圍。

    現在考慮MyClass的(相同的代碼)構造函數初始化列表

    // With Initializer List 
    class MyClass { 
    Type variable; 
    public: 
    MyClass(Type a):variable(a) { // Assume that Type is an already 
           // declared class and it has appropriate 
           // constructors and operators 
    } 
    }; 
    

    隨着初始化列表,下面的步驟之後編譯:

    1. 「類型」類的拷貝構造調用初始化:variable(a)。初始化列表中的參數用於直接複製構造「變量」。
    2. 「類型」的析構函數因爲超出範圍而被稱爲「a」。這裏
  • 10
    1. 基類的初始化

    一個使用未在答案中提到的構造函數初始化列表重要的原因是基類的初始化。

    根據構建順序,基類應該在子類之前構建。沒有構造函數初始化列表,如果你的基類有默認的構造函數,在進入子類的構造函數之前調用它,這是可能的。但是,如果你的基類只有參數化構造函數,那麼你必須使用構造函數初始化列表來確保你的基類在子類之前被初始化。

  • 子對象只具有參數化的構造

  • 效率

  • 使用構造函數初始化列表初始化的,您的數據成員初始化在代碼中需要的確切狀態,而不是首先將它們初始化爲默認狀態&然後將其狀態更改爲您需要的狀態你的代碼。

  • 初始化非靜態常量數據成員
  • 如果你的類的非靜態常量數據成員有默認構造函數&你不使用構造函數初始化列表,您將無法將它們初始化爲預期狀態,因爲它們將被初始化爲默認狀態。

    的基準數據成員
  • 初始化
  • 參考數據成員必須作爲參考,不能只是聲明&後初始化時編譯器進入構造函數intialized。這隻有在構造函數初始化列表中才有可能。

    0

    語法:

    class Sample 
        { 
        public: 
         int Sam_x; 
         int Sam_y; 
    
        Sample(): Sam_x(1), Sam_y(2)  /* Classname: Initialization List */ 
        { 
          // Constructor body 
        } 
        }; 
    

    初始化列表的極品:

    class Sample 
    { 
        public: 
         int Sam_x; 
         int Sam_y; 
    
        Sample()  */* Object and variables are created - i.e.:declaration of variables */* 
        { // Constructor body starts 
    
         Sam_x = 1;  */* Defining a value to the variable */* 
         Sam_y = 2; 
    
        } // Constructor body ends 
        }; 
    
    在上面的程序

    ,當執行類的構造函數,和Sam_y創建Sam_x。然後在構造函數體中,定義這些成員數據變量。

    用例:在一類

    在C

    1. CONST和參考變量,變量必須被創建期間定義。在C++中使用相同的方式,我們必須使用初始化列表在對象創建期間初始化Const和引用變量。如果我們在創建對象之後(內部構造函數體)進行初始化,我們會得到編譯時錯誤。

    2. 會員的Sample1的物體(基體),其不具有默認的構造

      class Sample1 
      { 
          int i; 
          public: 
          Sample1 (int temp) 
          { 
           i = temp; 
          } 
      }; 
      
          // Class Sample2 contains object of Sample1 
      class Sample2 
      { 
          Sample1 a; 
          public: 
          Sample2 (int x): a(x)  /* Initializer list must be used */ 
          { 
      
          } 
      }; 
      

    雖然這將在內部調用派生類的派生類創建對象類構造函數並調用基類構造函數(默認)。如果基類沒有默認構造函數,用戶將得到編譯時錯誤。爲了避免,我們必須具有

    1. Default constructor of Sample1 class 
    2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program) 
    
  • 一類的

    類構造函數的參數名稱和數據部件是相同的:

    class Sample3 { 
        int i;   /* Member variable name : i */ 
        public: 
        Sample3 (int i) /* Local variable name : i */ 
        { 
         i = i; 
         print(i); /* Local variable: Prints the correct value which we passed in constructor */ 
        } 
        int getI() const 
        { 
         print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/ 
         return i; 
        } 
    }; 
    
  • 大家都知道,具有最高優先級的局部變量然後是全局變量,如果兩個變量具有相同的名稱。在這種情況下,程序會考慮「i」值(左右變量)。即:i = i}作爲Sample3()構造函數中的局部變量,並且Class成員變量(i)被覆蓋。爲了避免,我們必須使用

    1. Initialization list 
        2. this operator. 
    
    相關問題