建構函式的初始化列表僅僅指定用於初始化成員的值,並不指定這些初始化執行的次序。成員初始化的次序就是定義成員的次序,第一個成員首先被初始化,然後是第二個,依次類推
首先,運行中的C++代碼,輸出是什嗎?
複製代碼 代碼如下:
class A
{
private:
int n1;
int n2;
public:
A(): n2(0) , n1(n2 + 2)
{
}
void Print()
{
cout<<"n1:"<<n1<<",n2:"<<n2<<endl;
}
};
int main(void)
{
A a;
a.Print();
return 0;
}
答案:
輸 出n1是一個隨機的數字,n2為0。在C++中,成員變數的初始化順序與變數在類型中的聲明順序相同,而與它們在建構函式的初始化列表中的順序無關。因此 在這道題中,會首先初始化n1,而初始n1的參數n2還沒有初始化,是一個隨機值,因此n1就是一個隨機值。初始化n2時,根據參數0對其初始化,故 n2=0。
建構函式的初始化列表僅僅指定用於初始化成員的值,並不指定這些初始化執行的次序。成 員初始化的次序就是定義成員的次序,第一個成員首先被初始化,然後是第二個,依次類推。也就是說,C++編譯器很容易得到建構函式的參數列表,擷取參數, 然後根據成員變數的聲明順序初始化成員變數(這是因為,後聲明的變數有可能依賴先聲明的成員變數,因此要有先聲明先初始化,後聲明的後初始化)。
大家可能看到這裡就會覺得,好麻煩啊,當類中的一個資料成員是根據其他資料成員而初始化的時候,初始化列表的次序不能跟成員變數的聲明次序不一致,否則會出現不可預料的錯誤。
的確是這樣的,所以有人就會想到,我乾脆把初始化列表的那些操作都放到建構函式的函數體內對資料成員進行賦值操作就行了,的確這樣做是可以的,但是有時建構函式的初始化列表是必須的。
有些資料成員必須在建構函式初始化列表中進行初始化。對於這樣的成員,在建構函式體內對它們賦值是不起作用的。沒有預設建構函式的類類型的成員,以及const類型的成員變數和參考型別的成員變數,不管是哪種類型,都必須在建構函式初始化列表中進行初始化。
例如,下面的建構函式定義就是錯誤的:
複製代碼 代碼如下:
class A
{
private:
int i;
const int j;
int &k;
public:
A(int ii)
{
i = ii;
j = ii;
k = ii;
}
};
記住,可以初始化 const 對象或參考型別的對象,但不能對它們賦值。在開始執行建構函式的函數體之前,要完成初始化,初始化 const 或參考型別的資料成員的唯一機會就是在建構函式的初始化列表中。
例如,下面的建構函式定義就是正確的:
複製代碼 代碼如下:
class A
{
private:
int i;
const int j;
int &k;
public:
A(int ii) : i(ii) , j(i) , k(ii)
{
}
A() : j(0) , k(i)
{ }
};
int main(void)
{
A a;
return 0;
}