構(gòu)造函數(shù) ,是一種特殊的方法 。主要用來(lái)在創(chuàng)建對(duì)象時(shí)初始化對(duì)象, 即為對(duì)象成員變量賦初始值,總與new運(yùn)算符一起使用在創(chuàng)建對(duì)象的語(yǔ)句中 。特別的一個(gè)類可以有多個(gè)構(gòu)造函數(shù) ,可根據(jù)其參數(shù)個(gè)數(shù)的不同或參數(shù)類型的不同來(lái)區(qū)分它們 即構(gòu)造函數(shù)的重載。(摘自百度百科 構(gòu)造函數(shù) )。
一、最基本的構(gòu)造函數(shù)
1 class Base2 {3 public:4 Base(int var) : m_Var(var)5 {6 }7 PRivate:8 int m_Var;9 };以上構(gòu)造函數(shù)的執(zhí)行過(guò)程:
1)傳參 2)給類數(shù)據(jù)成員開辟空間 3)執(zhí)行冒號(hào)語(yǔ)法給數(shù)據(jù)成員初始化 4)執(zhí)行構(gòu)造函數(shù)括號(hào)里面的內(nèi)容
這里需要說(shuō)明的是:冒號(hào)語(yǔ)法后面的內(nèi)容相當(dāng)于int a = 10;(初始化),而構(gòu)造函數(shù)括號(hào)里面則是相當(dāng)于是int a; a = 10;(賦初值)
二、拷貝構(gòu)造函數(shù)
1 class Base 2 { 3 public: 4 Base(int var) : m_Var(var) 5 { 6 } 7 //拷貝構(gòu)造函數(shù) 8 Base(Base &ref) : m_Var(ref.m_Var) 9 {10 }11 private:12 int m_Var;13 };為什么拷貝構(gòu)造函數(shù)的參數(shù)只能用引用呢?
這就要從拷貝構(gòu)造函數(shù)式數(shù)碼時(shí)候觸發(fā)開始說(shuō)起了,以下幾種情況都會(huì)自動(dòng)調(diào)用拷貝構(gòu)造函數(shù):
1)用一個(gè)已有的對(duì)象初始化一個(gè)新對(duì)象的時(shí)候
2)將一個(gè)對(duì)象以值傳遞的方式傳給形參的時(shí)候
3)函數(shù)返回一個(gè)對(duì)象的時(shí)候
所以當(dāng)一個(gè)對(duì)象以傳遞值的方式傳一個(gè)函數(shù)的時(shí)候,拷貝構(gòu)造函數(shù)自動(dòng)的被調(diào)用來(lái)生成函數(shù)中的對(duì)象。如果一個(gè)對(duì)象是被傳入自己的拷貝構(gòu)造函數(shù),它的拷貝構(gòu)造函數(shù)將會(huì)被調(diào)用來(lái)拷貝這個(gè)對(duì)象這樣復(fù)制才可以傳入它自己的拷貝構(gòu)造函數(shù),這會(huì)導(dǎo)致無(wú)限循環(huán)直至棧溢出除了當(dāng)對(duì)象傳入函數(shù)的時(shí)候被隱式調(diào)用以外,拷貝構(gòu)造函數(shù)在對(duì)象被函數(shù)返回的時(shí)候也同樣的被調(diào)用。(摘自百度百科 拷貝構(gòu)造函數(shù) )。
拷貝構(gòu)造函數(shù),一般不需要自己編寫,系統(tǒng)默認(rèn)的拷貝構(gòu)造函數(shù)就能抗住了,但是有些情況需要在構(gòu)造的時(shí)候開辟空間,這時(shí)候就需要拷貝構(gòu)造函數(shù)了,如下代碼是摘自 林銳 博士的 高質(zhì)量C++編程指南 一文。
1 class String 2 { 3 public: 4 String(const char *str = NULL); // 普通構(gòu)造函數(shù) 5 String(const String &other); // 拷貝構(gòu)造函數(shù) 6 ~ String(void); // 析構(gòu)函數(shù) 7 private: 8 char *m_data; // 用于保存字符串 9 };10 // String 的析構(gòu)函數(shù)11 String::~String(void) 12 {13 delete [] m_data;14 // 由于m_data 是內(nèi)部數(shù)據(jù)類型,也可以寫成 delete m_data;15 }16 17 // String 的普通構(gòu)造函數(shù)18 String::String(const char *str) 19 {20 if(str==NULL)21 {22 m_data = new char[1]; // 若能加 NULL 判斷則更好23 *m_data = '/0';24 }25 else26 {27 int length = strlen(str);28 m_data = new char[length+1]; // 若能加 NULL 判斷則更好29 strcpy(m_data, str);30 }31 }32 // 拷貝構(gòu)造函數(shù)33 String::String(const String &other) 34 {35 int length = strlen(other.m_data);36 m_data = new char[length+1]; // 若能加 NULL 判斷則更好37 strcpy(m_data, other.m_data);38 } 三、普通派生類構(gòu)造函數(shù)的寫法
定義派生類對(duì)象的時(shí)候,會(huì)按如下步驟執(zhí)行構(gòu)造操作:
1)傳參 2)根據(jù)繼承時(shí)的聲明順序構(gòu)造基類 3)給類數(shù)據(jù)成員開辟空間 4)執(zhí)行冒號(hào)語(yǔ)法后面的語(yǔ)句 5)執(zhí)行構(gòu)造函數(shù)函數(shù)體語(yǔ)句
1 class Base 2 { 3 public: 4 Base(int b) : m_b(b) 5 { 6 } 7 private: 8 int m_b; 9 };10 11 class Derived : public Base12 {13 public:14 //普通派生類構(gòu)造函數(shù)的寫法15 Derived(int b, int d) : Base(b), m_d(d)16 {17 }18 private:19 int m_d;20 };再寫一個(gè)多繼承的示例:
1 class Base1 2 { 3 public: 4 Base1(int b1) : m_b1(b1) 5 { 6 } 7 private: 8 int m_b1; 9 };10 11 class Base212 {13 public:14 Base2(int b2) : m_b2(b2)15 {16 }17 private:18 int m_b2;19 };20 21 class Derived : public Base1, public Base222 {23 public:24 Derived(int b1, int b2, int d) : Base1(b1), Base2(b2), m_d(d)25 { //注意冒號(hào)語(yǔ)法后面的順序無(wú)所謂,創(chuàng)造基類是按照上面的繼承聲明順序來(lái)進(jìn)行的...26 }27 private:28 int m_d;29 };四、含有虛繼承的派生類構(gòu)造函數(shù)的寫法
為何要用到虛繼承?
虛繼承主要是針對(duì)多繼承時(shí),出現(xiàn)二義性問(wèn)題而提出的。比如,如下代碼就需要用到虛繼承,否則的話Derived類繼承時(shí),Base類就會(huì)不明確。
虛繼承構(gòu)造函數(shù)的執(zhí)行按照如下步驟:
1)傳參 2)創(chuàng)建基類,注意這時(shí)候需要顯示創(chuàng)建所有“有參構(gòu)造函數(shù)”的基類,包括直接基類,間接基類。 3)給類數(shù)據(jù)成員開辟空間 4)執(zhí)行冒號(hào)語(yǔ)法 5)執(zhí)行構(gòu)造函數(shù)函數(shù)體
注:你可能會(huì)疑惑,如下代碼不是將Base間接基類創(chuàng)建了3次嗎?其實(shí)不是這樣的,編譯器是這樣處理的,當(dāng)最遠(yuǎn)的派生類Derived創(chuàng)建了基類Base之后,其直接基類創(chuàng)建Base類的語(yǔ)句將會(huì)被忽略掉。
1 class Base 2 { 3 public: 4 Base(int b) : m_b(b) 5 { 6 } 7 private: 8 int m_b; 9 };10 11 class Base1 : virtual public Base12 {13 public:14 Base1(int b, int b1) : Base(b), m_b1(b1)15 {16 }17 private:18 int m_b1;19 };20 21 class Base2 : virtual public Base22 {23 public:24 Base2(int b, int b2) : Base(b), m_b2(b2)25 {26 }27 private:28 int m_b2;29 };30 //虛繼承,避免二義性31 class Derived : public Base1, public Base232 {33 public:34 Derived(int b, int b1, int b2, int d) : Base(b), Base1(b, b1), Base2(b, b2), m_d(d)35 { //注意冒號(hào)語(yǔ)法后面的順序無(wú)所謂,創(chuàng)造基類是按照上面的繼承聲明順序來(lái)進(jìn)行的...36 }37 private:38 int m_d;39 };五、關(guān)于虛析構(gòu)
虛析構(gòu)一般伴隨著多態(tài)而產(chǎn)生,多態(tài)主要方式就是用基類的指針或引用指向或引用派生類,而形成多態(tài)。
但是這樣就會(huì)存在一個(gè)問(wèn)題,當(dāng)我們析構(gòu)的時(shí)候,由于是基類的指針,就會(huì)調(diào)用的是基類的構(gòu)造函數(shù),從而造成派生內(nèi)存溢出。為了解決這個(gè)問(wèn)題,引入了虛析構(gòu)的概念。將基類的構(gòu)造函數(shù)聲明為虛,從而使其在調(diào)用析構(gòu)函數(shù)的時(shí)候能夠準(zhǔn)確的調(diào)用派生類的析構(gòu)函數(shù)。
如下代碼必須用到虛析構(gòu)才能準(zhǔn)確的析構(gòu)派生類,并釋放其占有內(nèi)存。
1 class Base 2 { 3 public: 4 Base(int b) : m_b(b) 5 { 6 } 7 //虛析構(gòu),使基類指針能準(zhǔn)確的釋放所指向的派生類里面的內(nèi)容 8 virtual ~Base() 9 {10 }11 private:12 int m_b;13 };14 15 class Derived : public Base16 {17 public:18 Derived(int b, char *pStr) : Base(b)19 { 20 m_pStr = new char[strlen(pStr)+1];21 strcpy(m_pStr,pStr);22 }23 ~Derived()24 {25 delete m_pStr;26 m_pStr = NULL;27 }28 private:29 char *m_pStr;30 };31 32 int main(void)33 {34 char *pStr = "abcdefg";35 Base *b = new Derived(1,pStr);36 delete b;37 38 return 0;39 }
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注