C 使用初始化列表初始化資料成員的三種情況

2021-08-22 16:20:43 字數 2805 閱讀 5582

類物件的構造順序是這樣的:

1.分配記憶體,呼叫建構函式時,隱式/顯示的初始化各資料成員(建構函式列表的初始化方式不是按照列表的的順序,而是按照變數宣告的順序同時初始化顯隱資料成員);

2.進入建構函式後在建構函式中執行一般賦值與計算。

使用初始化列表有兩個原因:

原因1.必須這樣做:

《c++ primer》中提到在以下三種情況下需要使用初始化成員列表:

情況一、需要初始化的資料成員是物件的情況(這裡包含了繼承情況下,通過顯示呼叫父類的建構函式對父類資料成員進行初始化);  情況

二、需要初始化const修飾的類成員或初始化引用成員資料; 情況

三、子類初始化父類的私有成員;

■情況一的說明:資料成員是物件,並且這個物件只有含引數的建構函式,沒有無引數的建構函式;

如果我們有乙個類成員,它本身是乙個類或者是乙個結構,而且這個成員它只有乙個帶引數的建構函式,而沒有預設建構函式,這時要對這個類成員進行初始化,就必須呼叫這個類成員的帶引數的建構函式,如果沒有初始化列表,那麼他將無法完成第一步,就會報錯。

例子:

using namespace std;

class test

;private:

int x;

int y;

int z;

};class mytest

;private:

test test; //宣告

};int _tmain(int argc, _tchar* argv)

輸出結果:

①   如果沒有mytest():test(1,2,3){}初始化列表就會報錯:

因為test有了顯示的帶引數的建構函式,那麼他是無法依靠編譯器生成無參建構函式的,所以沒有三個int型資料,就無法建立test的物件。test類物件是mytest的成員,想要初始化這個物件test,那就只能用成員初始化列表,沒有其他辦法將引數傳遞給test類建構函式。

②初始化列表在建構函式執行前執行(這個可以看上面的結果,對同乙個變數在初始化列表和建構函式中分別初始化,首先執行引數列表,後在函式體內賦值,後者會覆蓋前者)。

■情況二的說明:物件引用或者cosnt修飾的資料成員

情況二:當類成員中含有乙個const物件時,或者是乙個引用時,他們也必須要通過成員初始化列表進行初始化,因為這兩種物件要在宣告後馬上初始化,而在建構函式中,做的是對他們的賦值,這樣是不被允許的。

例子:

class test

//初始化

};//或

class test

//初始化

}

■情況三的說明:子類初始化父類的私有成員,需要在(並且也只能在)引數初始化列表中顯示呼叫父類的建構函式:如下:

例子:

class test ;

test(int x) ;

void show()

private:

int int_x;

};class mytest :public test ;

};int _tmain(int argc, _tchar* argv)

結果:如果在建構函式內部被顯示呼叫輸出結果是:-842150451(原因是雖然呼叫了 test (int x),但是直接呼叫建構函式產生了乙個臨時物件,而不是呼叫父類的建構函式來構造父類的私有變數,作用域只在一條語句中,所以相當於什麼都沒做。故而直接列印出乙個隨機值。);

如果在初始化列表中被顯示呼叫輸出結果是:110

原因2.效率要求這樣做:

類物件的構造順序顯示,進入建構函式體後,進行的是計算,是對成員變數的賦值操作,顯然,賦值和初始化是不同的,這樣就體現出了效率差異,如果不用成員初始化類表,那麼類對自己的類成員分別進行的是一次隱式的預設建構函式的呼叫,和一次賦值操作符的呼叫,如果是類物件,這樣做效率就得不到保障。

注意:建構函式需要初始化的資料成員,不論是否顯示的出現在建構函式的成員初始化列表中,都會在該處完成初始化,並且初始化的順序和其在類中宣告時的順序是一致的,與列表的先後順序無關,所以要特別注意,保證兩者順序一致才能真正保證其效率和準確性。

為了說明清楚,假設有這樣乙個類:

class foo

;

①、foo(){}和foo(int i = 0){}都被認為是預設建構函式,因為後者是預設引數。兩者不能同時出現。

②建構函式列表的初始化方式不是按照列表的的順序,而是按照變數宣告的順序。比如foo裡面,a在b之前,那麼會先構造a再構造b。所以無論foo():a(b + 1), b(2){}還是foo():b(2),a(b+1){}都不會讓a得到期望的值。

③建構函式列表能夠對const成員初始化。比如foo裡面有乙個int const c;則foo(int x) : c(x){}可以讓c值賦成x。

不過需要注意的是,c必須在每個建構函式(如果有多個)都有值。

④在繼承裡面,只有初始化列表可以構造父類的private成員(通過顯示呼叫父類的建構函式)。比如說:

class child : public foo{};

//foo裡面的建構函式是這樣寫的:

foo (int x)

而在child裡面寫child(int x)是通過不了編譯的。

只有把子類建構函式寫作child(int x) : foo(x){}才可以。

成員初始化列表

類物件的構造順序是這樣的 1.分配記憶體,呼叫建構函式時,隱式 顯示的初始化各資料成員 初始化階段可以是顯式的或隱式的,取決於是否存在成員初始化表。隱式初始化階段按照宣告的順序依次呼叫所有基類的預設建構函式,然後是所有成員類物件的預設建構函式。2.進入建構函式後在建構函式中執行一般計算 計算階段由建...

成員初始化列表

任乙個物件的建立都要呼叫建構函式,而在建構函式中一般要給物件屬性賦值。成員初始化列表 member initialize list 是建構函式中特有的語法,用以簡化對物件屬性的賦值。其用法如下 class myclass 以上 相當於 class myclass 用成員初始化列表的語法來表述很顯然 ...

成員初始化列表

從概念上講,可以認為建構函式分兩個階段執行 1 初始化階段 2 普通的計算階段。計算階段由建構函式函式體中的所有語句組成。不管成員是否在建構函式初始化列表中顯式初始化,類型別的資料成員總是在初始化階段初始化。初始化發生在計算階段開始之前。在建構函式初始化列表中沒有顯式提及的每個成員,使用與初始化變數...