從概念上講,可以認為建構函式分兩個階段進行:
1.初始化階段;
2.普通的計算階段。(計算階段由建構函式函式體中的所有語句組成)
不管成員是否在建構函式初始化列表中顯示初始化,類型別的資料成員總是在初始化階段初始化。初始化發生在計算階段的開始之前。
建議:使用建構函式初始化列表
注:必須對任何const或引用型別成員以及沒有預設建構函式的類型別的任何成員使用初始化式。
一般使用建構函式初始化列表,可以避免發生編譯錯誤。
講解:沒有預設建構函式的類?是什麼意思?
在大部分編譯器中,宣告乙個類,若類沒有顯示的宣告和定義建構函式,那麼編譯器就會在編譯階段生成乙個預設建構函式。如果使用者在該類中宣告了乙個建構函式,那麼編譯器就不會生成預設建構函式,而是使用了使用者自己定義的建構函式,為了避免編譯錯誤,最好使用建構函式初始化列表對該類的物件進行初始化。
-----摘自於《c++ primer 中文版 第4版》
類成員的初始化包括類物件成員與類資料成員的初始化。初始化比較關鍵的是建構函式的初始化列表,在建構函式中成員初始化列表中也需要次序的。只有建構函式才能有成員初始化的效果,普通的成員函式沒有這功能,比如:
[cpp]view plain
copy
void
cinit::setxy(
intx,
inty) : mx(x), my(y)
這個初始化是錯誤的,setxy並非是建構函式,所以普通成員函式只能通過賦值的形式來設定變數或物件的值。
[cpp]view plain
copy
void
cinit::setxy(
intx,
inty)
這裡宣告乙個類cinit,如下:
[cpp]view plain
copy
class
cinit
; void
cinit::show()
const
一.建構函式的初始化列表的基本使用
這是正常的初始化列表的用法
初始化:
[cpp]view plain
copy
cinit::cinit(
intx,
inty) : mx(x), my(y)
達到的結果相當於
賦值:
[cpp]view plain
copy
cinit::cinit(
intx,
inty)
二.成員初始化的次序
在建構函式初始化列表中,成員初始化的次序就是宣告成員的次序。
例子1:張三想先用x初始化mx,再用mx初始化my
[cpp]view plain
copy
cinit::cinit(
intx,
inty) : mx(x), my(mx)
cinit test(2, 3);
test.show();
此時的結果是:
[plain]view plain
copy
mx = 2
my = 2
mx與my均被成功的初始化。
例子2:李四想先初始化my,再用my初始化mx
[cpp]view plain
copy
cinit::cinit(
intx,
inty) : my(y), mx(my)
cinit test(2, 3);
test.show();
此時的結果是:
[plain]view plain
copy
mx = 2147344384 (不同機器可能不一致)
my = 3
從結果可以很明顯的看出,mx沒有被初始化,而my成功被初始化為3。
從這裡可以看出,建構函式是以變數的宣告順序來執行初始化的動作,所以例子2中,建構函式先初始化mx,但此時my是未初始化過的,所以導致這種情況。在建構函式的初始化列表中,最好要按照類中成員變數的宣告順序來初始化。
三.在什麼情況下使用建構函式初始化列表?
1.const物件
2.引用型別物件
因為const物件與引用型別物件只能夠初始化,不能賦值,所以必須在初始化列表中進行初始化。
3.類物件(下文說明)
四.建構函式中,賦值初始化與初始化列表初始化,哪個效率更高?為什麼?
先來看乙個例子,便可知分曉:
[cpp]view plain
copy
#include
using
namespace
std;
class
cobj
cobj(const
cobj &obj)
cobj & operator=(const
cobj &obj)
cout << "資料賦值"
<< endl;
return
*this
; }
private
: int
mx;
};
class
cinit
private
: cobj mobj;
};
intmain()
1.若cinit的建構函式為:
[cpp]view plain
copy
cinit(
const
cobj & obj) : mobj(obj)
執行結果為:
[plain]view plain
copy
呼叫預設建構函式
呼叫複製建構函式
在建構函式cinit的初始化列表初始化mobj物件時,呼叫了複製建構函式1次,總共需要1個行為。
2.若cinit的建構函式為:
[cpp]view plain
copy
cinit(
const
cobj & obj)
執行結果為:
[plain]view plain
copy
呼叫預設建構函式
呼叫預設建構函式
資料賦值
在建構函式體中賦值mobj物件時,首先呼叫預設建構函式,其次是呼叫operator=賦值運算子,總共需要2個行為。
所以可以得出這麼乙個結論:對於使用者自定義的類型別,使用建構函式初始化列表進行初始化的效率,比在建構函式體中賦值初始化的效率更高。對於內建型別,效率是差不多的。
五.建構函式初始化列表的使用例子
[cpp]view plain
copy
/*類成員的初始化: 求2點組成的矩形*/
#include
using
namespace
std;
class
ccenterpoint
void
showpos()
const
private
: int
mposx;
intmposy;
};
class
carea
void
showarea()
const
private
: int
mlength;
intmwidth;
};
class
crect
void
show()
const
private
: ccenterpoint mpoint;
carea marea;
};
intmain()
執行結果:
[plain]view plain
copy
2點之間的中點座標: (55,110)
2點組成的矩形面積: 1000
C 建構函式 ,初始化列表
c 中的類的建構函式 1.如果類中沒有定義建構函式,編譯器將生成乙個預設建構函式,這個預設建構函式會呼叫類中所有成員的預設建構函式,但不會對如int,double的基本資料型別做初始化 2.類中可以定義多個建構函式,但每個建構函式應該有不同的引數實現 3.預設建構函式必須定義的情況,當需要定義乙個物...
C 建構函式初始化列表
建構函式初始化列表以乙個冒號開始,接著是以逗號分隔的資料成員列表,每個資料成員後面跟乙個放在括號中的初始化式。例如 example example ival 0 dval 0.0 ival 和dval是類的兩個資料成員 上面的例子和下面不用初始化列表的建構函式看似沒什麼區別 example exam...
C 建構函式初始化列表
建構函式初始化列表是乙個重要的概念,這一步是建構函式執行時無論如何也要走的一步。建構函式可以說成三部分構成,1 引數列表 2 初始化列表 3 函式體。其中初始化列表是可選的。在一定情況下不需要初始化列表。以下是c primer上面的一段 sales item sales item const str...