您好,登錄后才能下訂單哦!
類對(duì)象的構(gòu)造順序是這樣的:
1.分配內(nèi)存,調(diào)用構(gòu)造函數(shù)時(shí),隱式/顯示的初始化各數(shù)據(jù)成員
2.進(jìn)入構(gòu)造函數(shù)后在構(gòu)造函數(shù)中執(zhí)行一般計(jì)算
使用初始化列表有兩個(gè)原因:
1.必須這樣做:
《C++ Primer》中提到在以下三種情況下需要使用初始化成員列表:
一、需要初始化的數(shù)據(jù)成員是對(duì)象的情況;
二、需要初始化const修飾的類成員;
三、需要初始化引用成員數(shù)據(jù);
如果我們有一個(gè)類成員,它本身是一個(gè)類或者是一個(gè)結(jié)構(gòu),而且這個(gè)成員它只有一個(gè)帶參數(shù)的構(gòu)造函數(shù),而沒有默認(rèn)構(gòu)造函數(shù),這時(shí)要對(duì)這個(gè)類成員進(jìn)行初始化,就必須調(diào)用這個(gè)類成員的帶參數(shù)的構(gòu)造函數(shù),如果沒有初始化列表,那么他將無法完成第一步,就會(huì)報(bào)錯(cuò)。
class ABC
...{
public:
ABC(int x,int y,int z);
private:
int a;
int b;
int c;
};
class MyClass
...{
public:
MyClass():abc(1,2,3)...{}
private:
ABC abc;
};
因?yàn)锳BC有了顯示的帶參數(shù)的構(gòu)造函數(shù),那么他是無法依靠編譯器生成無參構(gòu)造函數(shù)的,所以沒有三個(gè)int型數(shù)據(jù),就無法創(chuàng)建ABC的對(duì)象。
ABC類對(duì)象是MyClass的成員,想要初始化這個(gè)對(duì)象abc,那就只能用成員初始化列表,沒有其他辦法將參數(shù)傳遞給ABC類構(gòu)造函數(shù)。
另一種情況是這樣的:當(dāng)類成員中含有一個(gè)const對(duì)象時(shí),或者是一個(gè)引用時(shí),他們也必須要通過成員初始化列表進(jìn)行初始化,因?yàn)檫@兩種對(duì)象要在聲明后馬上初始化,而在構(gòu)造函數(shù)中,做的是對(duì)他們的賦值,這樣是不被允許的。
2.效率要求這樣做:
類對(duì)象的構(gòu)造順序顯示,進(jìn)入構(gòu)造函數(shù)體后,進(jìn)行的是計(jì)算,是對(duì)他們的賦值操作,顯然,賦值和初始化是不同的,這樣就體現(xiàn)出了效率差異,如果不用成員初始化類表,那么類對(duì)自己的類成員分別進(jìn)行的是一次隱式的默認(rèn)構(gòu)造函數(shù)的調(diào)用,和一次復(fù)制操作符的調(diào)用,如果是類對(duì)象,這樣做效率就得不到保障。
注意:構(gòu)造函數(shù)需要初始化的數(shù)據(jù)成員,不論是否顯示的出現(xiàn)在構(gòu)造函數(shù)的成員初始化列表中,都會(huì)在該處完成初始化,并且初始化的順序和其在聲明時(shí)的順序是一致的,與列表的先后順序無關(guān),所以要特別注意,保證兩者順序一致才能真正保證其效率。
為了說明清楚,假設(shè)有這樣一個(gè)類:
class foo{
private :
int a, b;
};
1、foo(){}和foo(int i = 0){}都被認(rèn)為是默認(rèn)構(gòu)造函數(shù),因?yàn)楹笳呤悄J(rèn)參數(shù)。兩者不能同時(shí)出現(xiàn)。
2、構(gòu)造函數(shù)列表的初始化方式不是按照列表的的順序,而是按照變量聲明的順序。比如foo里面,a在b之前,那么會(huì)先構(gòu)造a再構(gòu)造b。所以無論 foo():a(b + 1), b(2){}還是foo():b(2),a(b+1){}都不會(huì)讓a得到期望的值。如果先聲明b再聲明a則會(huì)更好。
3、構(gòu)造函數(shù)列表能夠?qū)onst成員初始化。比如foo里面有一個(gè)int const c;則foo(int x) : c(x){}可以讓c值賦成x。不過需要注意的是,c必須在每個(gè)構(gòu)造函數(shù)(如果有多個(gè))都有值。
4、在繼承里面,只有初始化列表可以構(gòu)造父類的private成員。比如說
class child : public foo{
}
foo里面的構(gòu)造函數(shù)是這樣寫的:foo (int x) { a = x; }.
而在child里面寫child(int x){ foo(x); }是通過不了編譯的。只有把父類初始化改為foo(int x) : a(x){}而子類構(gòu)造寫作child (int x) : foo(x){}才可以。
另一篇關(guān)于初始化列表的文章:
C++初始化類的成員,不但可以用構(gòu)造函數(shù)(constructor)完成,而且可以用初始化類成員列表來完成。MFC大量用到此方法。例如有些初學(xué)者可能不大理解如下代碼:
class A
{
public:
int member_var; //成員變量
A(); //構(gòu)造函數(shù)
}
A::A():member_var(0)
{
}
他們覺得這個(gè)構(gòu)造函數(shù)的定義應(yīng)該只能這樣寫:
A::A()
{
member_var=1;
}
其實(shí)兩種方法都可。但是有些情況下,只能用第一種,而且通常情況下用第一種也會(huì)效率高些。
其實(shí),第一種方法是真正的初始化(initialization),而在構(gòu)造函數(shù)內(nèi)實(shí)現(xiàn)的“=”操作其實(shí)是賦值(assign)。這兩種方法的一切區(qū)別從這兒開始。區(qū)別大概如下:
我們知道普通變量編譯器都會(huì)默認(rèn)的替你初始化。他們既能初始化,也能被賦值的,而常量(const)按照其意思只能被初始化,不能賦值。否則與變量就無區(qū)別了。所以常量成員(const member)只能用成員初始化列表來完成他們的“初始化”,而不能在構(gòu)造函數(shù)內(nèi)為他們“賦值”。
我們知道類的對(duì)象的初始化其實(shí)就是調(diào)用他的構(gòu)造函數(shù)完成,如果沒有寫構(gòu)造函數(shù),編譯器會(huì)為你默認(rèn)生成一個(gè)。如果你自定義了帶參數(shù)的構(gòu)造函數(shù),那么編譯器將不生成默認(rèn)構(gòu)造函數(shù)。這樣這個(gè)類的對(duì)象的初始化必須有參數(shù)。如果這樣的類的對(duì)象來做另外某個(gè)類的成員,那么為了初始化這個(gè)成員,你必須為這個(gè)類的對(duì)象的構(gòu)造函數(shù)傳遞一個(gè)參數(shù)。同樣,如果你在包含它的這個(gè)類的構(gòu)造函數(shù)里用“=”,其實(shí)是為這個(gè)對(duì)象“賦值”而非“初始化”它。所以一個(gè)類里的所有構(gòu)造函數(shù)都是有參數(shù)的,那么這樣的類如果做為別的類的成員變量,你必須顯式的初始化它,你也是只能通過成員初始化列表來完成初始化。例如:
class B
{
......
}
class A
{
public:
B member_b;
A();
}
A::A():B(...) //你必須顯式初始化它,因?yàn)樗乃袠?gòu)造函數(shù)
//都是有參數(shù)的,之后才能被賦值。
{
B=...; //因?yàn)槿缟纤鶎?,已?jīng)初始化了,才能被賦值,否則錯(cuò)誤。
}
——————————————————————————————————————
初始化順序:
class test
{
const int a;
std:string str;
object o;
test():str(“df”),o(null),a(0)
{
}
};
×××的既是初始化列表,他們會(huì)在構(gòu)造函數(shù)正式調(diào)用前被調(diào)用,且他們的初始化順序并不是根據(jù) 初始化列表中出現(xiàn)的順序,而是他們聲明的順序來初始化。如上:
初始化順序是:a, str, o;
一般用于初始化 常量類型,靜態(tài)類型的數(shù)據(jù),或者不能獨(dú)立存在的數(shù)據(jù)
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。