首先 放另外一個博主的鏈接:http://www.cnblogs.com/graphics/archive/2010/07/04/1770900.html
在學習c++構造函數的過程中遇到了初始化列表這個詞,便主動搜索資料,學習初始化列表這個概念
一、初始化列表的由來
在構造函數中,除了 函數名,函數體外,可以有初始化列表,也可以沒有初始化列表,初始化列表不是必須的。
struct Test
{
public:
Test(string n, int b): name(n), id(b){};//初始化列表的表現形式 :初始化列表以冒號開頭,后跟一系列以逗號分隔的初始化字段
// Test(string n, int b)
// {
// name = n;
// id = b;
//} 一般的構造函數
private:
string name;
int id;
};
在構造函數中,構造函數分兩步給成員變量賦值,第一是初始化階段,第二是計算階段,並且初始化階段在前,計算階段在后。
初始化階段:
所有類類型(class type)的成員都會在初始化階段初始化,即使該成員沒有出現在構造函數的初始化列表中。意思需初始化的成員沒有在初始化列表中,就會調用相應的構造函數來進行初始化,如默認構造函數,一般帶參構造函數,復制構造函數,類型轉換構造函數等。
計算階段:
一般用於執行構造函數體內的賦值操作
我理解的賦值操作就是構造函數中函數體內部的操作,
struct Test1 {
Test1() // 無參構造函數
{ cout << "Construct Test1" << endl ;
}
Test1(const Test1& t1) // 拷貝構造函數
{ cout << "Copy constructor for Test1" << endl ;
this->a = t1.a ;
}
Test1& operator = (const Test1& t1) // 賦值運算符
{
cout << "assignment for Test1" << endl ;
this->a = t1.a ;
return *this;
}
int a ;
};
struct Test2 {
Test1 test1 ; //成員變量
Test2(Test1 &t1) //構造函數
{ test1 = t1 ;
}
};
執行代碼:
Test1 t1; // 會調用Test1 的默認構造函數,打印 Construct Test1
Test2(t1); //打印Construct Test1:因為 Test2 中有 test1 的成員變量,在它的初始化階段 會調用Test1 默認的構造函數,
// 打印 assignment for Test1 , 是在調用Test2的構造函數階段, 賦值操作,用到的是=號的重載。
二、成員變量如何初始化
1、用初始化列表初始化, 初始化列表是用來初始化成員變量的。
2、在構造函數中,用賦值語句進行初始化。
三、初始化列表有什么好處
使用初始化列表主要是基於性能問題,使用初始化列表少了一次調用默認構造函數的過程,當成員變量多的時候,這樣比較快。快才是硬道嘛。
struct Test2
{
Test1 test1 ;
Test2(Test1 &t1):test1(t1){}
}
這樣寫的話,Test2的初始化列表,直接調用拷貝構造函數初始化test1,就不會調用Test1 的默認構造函數了。 這樣效率更高。
四、那些必須使用初始化列表初始化
1、常量成員,因為常量只能初始化不能賦值,所以必須放在初始化列表里面
2、引用類型,引用必須在定義的時候初始化,並且不能重新賦值,所以也要寫在初始化列表里面。
3、沒有默認構造函數的類類型,因為使用初始化列表可以不必調用默認構造函數來初始化,而是直接調用拷貝構造函數初始化。
注:沒有默認構造函數的類的類型如果不用初始化列表來初始化就會調用默認的構造函數,但是它又沒有默認的構造函數,就會報錯。----billadd
大牛總結:
1. 如果我們有一個類成員,它本身是一個類或者是一個結構,而且這個成員它只有一個帶參數的構造函數, 而沒有默認構造函數,這時要對這個類成員進行初始化,就必須調用這個類成員的帶參數的構造函數, 如果沒有初始化列表,那么他將無法完成第一步,就會報錯。
2、類成員中若有const修飾,必須在對象初始化的時候,給const int m 賦值 當類成員中含有一個const對象時,或者是一個引用時,他們也必須要通過成員初始化列表進行初始化, 因為這兩種對象要在聲明后馬上初始化,而在構造函數中,做的是對他們的賦值,這樣是不被允許的。
舉例:
struct Test2
{
Test1 test1;
Test1 &aaa;
const int m;
Test2(Test1 &t1):test1(t1), m(10),aaa(test1){}
};
五、類中變量初始化的順序
成員是按照他們在類中出現的順序進行初始化的,而不是按照他們在初始化列表出現的順序初始化的
struct foo
{
int i ;
int j ;
foo(int x):i(x), j(i){}; // ok, 先初始化i,后初始化j
};
個人總結:
1、構造函數中可以有初始化列表,也可以沒有初始化列表
2、構造函數分為初始化和計算兩個階段,初始化階段在前,計算階段在后。
3、用初始化列表初始化變量比一般的賦值函數快,因為省去了調用默認構造函數。
4、常量變量、引用、無默認構造函數的類,必須用初始化列表初始化。
5、初始化列表的順序,是根據在類中出現的順序初始化的。
備注:dm10_init_list.cpp
