與其他函式不同,建構函式除了有名字,引數列表和函式體之外,還可以有初始化列表,初始化列表以冒號開頭,後跟一系列以逗號分隔的初始化字段。
例如:
struct foo
; // 初始化列表
};
初始化類的成員有兩種方式,一是使用初始化列表,二是在建構函式體內進行賦值操作。使用初始化列表主要是基於效能問題,對於內建型別,如int, float等,使用初始化類表和在建構函式體內初始化差別不是很大,但是對於類型別來說,最好使用初始化列表,使用初始化列表少了一次呼叫預設建構函式的過程,這對於資料密集型的類來說,是非常高效的。綜上,使用初始化列表有兩個原因:
原因1.必須這樣做:
《c++ primer》中提到在以下三種情況下需要使用初始化成員列表:
情況一、類成員為沒有預設建構函式的類型別
情況二、const修飾的類成員或引用成員資料;
情況三、子類初始化父類的私有成員;如果類存在繼承關係,派生類必須在其初始化列表中呼叫基類的建構函式
對於情況一的說明:資料成員是物件,並且這個物件只有含引數的建構函式,沒有無引數的建構函式;
如果我們有乙個類成員,它本身是乙個類或者是乙個結構,而且這個成員它只有乙個帶引數的建構函式,而沒有預設建構函式,這時要對這個類成員進行初始化,就必須呼叫這個類成員的帶引數的建構函式,如果沒有初始化列表,那麼他將無法完成第一步,就會報錯。
看乙個例子:
struct test1
test1(const test1& t1) // 拷貝建構函式
test1& operator = (const test1& t1) // 賦值運算子
int a ;
};struct test2
};int main()
輸出:
第一行輸出對應呼叫**中第一行,構造乙個test1物件。第二行輸出對應test2建構函式中的**,用預設的建構函式初始化物件test1,這就是所謂的初始化階段。第三行輸出對應test1的賦值運算子,對test1執行賦值操作,這就是所謂的計算階段。
對於這個例子,如果test2中使用初始化列表:
struct test2
}
輸出如下:
這種形式來初始化test1,那麼呼叫的時候就會直接使用test1的拷貝建構函式,而不會是先呼叫無參建構函式再對其進行賦值操作了,這於資料密集型的類來說,是非常高效的。
原因2.效率要求這樣做:
類物件的構造順序顯示,進入建構函式體後,進行的是計算,是對成員變數的賦值操作,顯然,賦值和初始化是不同的,這樣就體現出了效率差異,如果不用成員初始化類表,那麼類對自己的類成員分別進行的是一次隱式的預設建構函式的呼叫,和一次賦值操作符的呼叫,如果是類物件,這樣做效率就得不到保障。
注意:建構函式需要初始化的資料成員,不論是否顯示的出現在建構函式的成員初始化列表中,都會在該處完成初始化,並且初始化的順序和其在類中宣告時的順序是一致的,與列表的先後順序無關,所以要特別注意,保證兩者順序一致才能真正保證其效率和準確性。
注意:
1、建構函式列表的初始化方式不是按照列表的的順序,而是按照變數宣告的順序。所以,乙個好的習慣是,按照成員定義的順序進行初始化。
2、在子類中,只有初始化列表可以構造父類的private成員(通過顯示呼叫父類的建構函式)。
3、乙個好的原則是,能使用初始化列表的時候盡量使用初始化列表。
C 建構函式 ,初始化列表
c 中的類的建構函式 1.如果類中沒有定義建構函式,編譯器將生成乙個預設建構函式,這個預設建構函式會呼叫類中所有成員的預設建構函式,但不會對如int,double的基本資料型別做初始化 2.類中可以定義多個建構函式,但每個建構函式應該有不同的引數實現 3.預設建構函式必須定義的情況,當需要定義乙個物...
C 建構函式初始化列表
從概念上講,可以認為建構函式分兩個階段進行 1.初始化階段 2.普通的計算階段。計算階段由建構函式函式體中的所有語句組成 不管成員是否在建構函式初始化列表中顯示初始化,類型別的資料成員總是在初始化階段初始化。初始化發生在計算階段的開始之前。建議 使用建構函式初始化列表 注 必須對任何const或引用...
C 建構函式初始化列表
建構函式初始化列表以乙個冒號開始,接著是以逗號分隔的資料成員列表,每個資料成員後面跟乙個放在括號中的初始化式。例如 example example ival 0 dval 0.0 ival 和dval是類的兩個資料成員 上面的例子和下面不用初始化列表的建構函式看似沒什麼區別 example exam...