C++中的构造函数
文章目錄
- 1 構(gòu)造函數(shù)的基本概念
- 1.1 構(gòu)造函數(shù)的作用
- 1.2 構(gòu)造函數(shù)的特點
- 1.3 構(gòu)造函數(shù)的種類
- 2 默認(rèn)構(gòu)造函數(shù)
- 2.1 合成的默認(rèn)構(gòu)造函數(shù)
- 2.2 手動定義的默認(rèn)構(gòu)造函數(shù)
- 3 自定義的重載構(gòu)造函數(shù)
- 3.1 自定義的重載構(gòu)造函數(shù)
- 3.2 創(chuàng)建對象的幾種方式
- 3.3 手工調(diào)用構(gòu)造函數(shù)
- 4 拷貝構(gòu)造函數(shù)
- 4.1 合成的拷貝構(gòu)造函數(shù)
- 4.2 手動定義的拷貝構(gòu)造函數(shù)
- 4.3 拷貝構(gòu)造函數(shù)的調(diào)用時機(jī)
- 4.4 繼承關(guān)系中的拷貝構(gòu)造函數(shù)
- 5 賦值構(gòu)造函數(shù)
- 5.1 合成的賦值構(gòu)造函數(shù)
- 5.2 自定義的賦值構(gòu)造函數(shù)
- 6 在已經(jīng)申請的空間上調(diào)用構(gòu)造函數(shù)
1 構(gòu)造函數(shù)的基本概念
1.1 構(gòu)造函數(shù)的作用
構(gòu)造函數(shù)的作用:
- 在創(chuàng)建一個新的對象時,自動調(diào)用的函數(shù),用來進(jìn)行“初始化”工作。
- 對這個對象內(nèi)部的數(shù)據(jù)成員進(jìn)行初始化。
1.2 構(gòu)造函數(shù)的特點
構(gòu)造函數(shù)的特點:
- 自動調(diào)用(在創(chuàng)建新對象時,自動調(diào)用)。
- 構(gòu)造函數(shù)的函數(shù)名,和類名相同。
- 構(gòu)造函數(shù)沒有返回類型。
- 可以有多個構(gòu)造函數(shù)(即函數(shù)重載形式)。
1.3 構(gòu)造函數(shù)的種類
構(gòu)造函數(shù)的種類:
- 默認(rèn)構(gòu)造函數(shù)
- 自定義的構(gòu)造函數(shù)
- 拷貝構(gòu)造函數(shù)
- 賦值構(gòu)造函數(shù)
2 默認(rèn)構(gòu)造函數(shù)
沒有參數(shù)的構(gòu)造函數(shù),稱為默認(rèn)構(gòu)造函數(shù)。
2.1 合成的默認(rèn)構(gòu)造函數(shù)
當(dāng)類中沒有定義任何構(gòu)造函數(shù)時,編譯器默認(rèn)提供一個無參構(gòu)造函數(shù),并且其函數(shù)體為空:
- 如果數(shù)據(jù)成員使用了“類內(nèi)初始值”,就使用這個值來初始化數(shù)據(jù)成員。【C++11】
- 否則,就使用默認(rèn)初始化(實際上,不做任何初始化)
注意:
只要手動定義了任何一個構(gòu)造函數(shù)(包括拷貝構(gòu)造函數(shù)),編譯器就不會生成“合成的默認(rèn)構(gòu)造函數(shù)”。一般情況下,都應(yīng)該定義自己的構(gòu)造函數(shù),不要使用“合成的默認(rèn)構(gòu)造函數(shù)”,僅當(dāng)數(shù)據(jù)成員全部使用了“類內(nèi)初始值”,才宜使用“合成的默認(rèn)構(gòu)造函數(shù)”。
2.2 手動定義的默認(rèn)構(gòu)造函數(shù)
手動定義的默認(rèn)構(gòu)造函數(shù),常稱為“默認(rèn)構(gòu)造函數(shù)”。
Human::Human() {name = "無名氏";age = 18;salary = 30000; }int main(void) {Human h1; // 使用自定義的默認(rèn)構(gòu)造函數(shù)cout << "姓名:" << h1.getName() << endl;cout << "年齡: " << h1.getAge() << endl; cout << "薪資:" << h1.getSalary() << endl; system("pause");return 0; }說明: 如果某數(shù)據(jù)成員使用類內(nèi)初始值,同時又在構(gòu)造函數(shù)中進(jìn)行了初始化,那么以構(gòu)造函數(shù)中的初始化為準(zhǔn)。相當(dāng)于構(gòu)造函數(shù)中的初始化,會覆蓋對應(yīng)的類內(nèi)初始值。
3 自定義的重載構(gòu)造函數(shù)
3.1 自定義的重載構(gòu)造函數(shù)
自定義的重載構(gòu)造函數(shù)比較簡單,示例代碼如下:
Human::Human() {name = "無名氏";age = 18;salary = 30000; }Human::Human(int age, int salary) {cout << "調(diào)用自定義的構(gòu)造函數(shù)" << endl; this->age = age; //this是一個特殊的指針,指向這個對象本身this->salary = salary;name = "無名"; }int main(void) {Human h1(25, 35000); // 使用自定義的默認(rèn)構(gòu)造函數(shù)cout << "姓名:" << h1.getName() << endl;cout << "年齡: " << h1.getAge() << endl; cout << "薪資:" << h1.getSalary() << endl; system("pause");return 0; }3.2 創(chuàng)建對象的幾種方式
#include <stdio.h>class Test { public:Test() { printf("Test()\n");}Test(int v) { printf("Test(int v), v = %d\n", v);} };int main() {Test t; // 第一種:調(diào)用 Test()Test t1(1); // 第二種:調(diào)用 Test(int v)Test t2 = 2; // 第三種:調(diào)用 Test(int v)Test t3 = Test(); // 第4種:調(diào)用Test()int i(100);printf("i = %d\n", i);return 0; }3.3 手工調(diào)用構(gòu)造函數(shù)
一般情況下,構(gòu)造函數(shù)在對象定義時被自動調(diào)用;但是在一些特殊情況下,我們需要手工調(diào)用構(gòu)造函數(shù)。
創(chuàng)建對象數(shù)組就需要手工調(diào)用構(gòu)造函數(shù):
#include <stdio.h>class Test { private:int m_value; public:Test() { printf("Test()\n");m_value = 0;}Test(int v) { printf("Test(int v), v = %d\n", v);m_value = v;}int getValue(){return m_value;} };int main() {Test ta[3] = {Test(), Test(1), Test(2)}; for(int i=0; i<3; i++){printf("ta[%d].getValue() = %d\n", i , ta[i].getValue());}Test t = Test(100);printf("t.getValue() = %d\n", t.getValue());return 0; }4 拷貝構(gòu)造函數(shù)
4.1 合成的拷貝構(gòu)造函數(shù)
當(dāng)類中沒有定義拷貝構(gòu)造函數(shù)時,編譯器默認(rèn)提供也給拷貝構(gòu)造函數(shù),簡單的進(jìn)行成員變量的復(fù)制。編譯器默認(rèn)提供的拷貝構(gòu)造函數(shù)也叫合成的拷貝構(gòu)造函數(shù),合成的拷貝構(gòu)造函數(shù)使用“淺拷貝”。
拷貝構(gòu)造函數(shù)的意義:
- 兼容C語言的初始化方式。
- 初始化行為能夠符合預(yù)期的邏輯。
拷貝構(gòu)造函數(shù)分為淺拷貝和深拷貝:
- 淺拷貝:拷貝后對象的物理狀態(tài)相同。
- 深拷貝:拷貝后對象的邏輯狀態(tài)相同。
當(dāng)對象中有成員指代了系統(tǒng)的資源,我么需要進(jìn)行深拷貝:
- 成員指向了動態(tài)內(nèi)存空間。
- 成員打開了外存中的文件。
- 成員使用了系統(tǒng)中的網(wǎng)絡(luò)端口。
- …
編譯器提供的拷貝構(gòu)造函數(shù)只進(jìn)行淺拷貝!
4.2 手動定義的拷貝構(gòu)造函數(shù)
一般性原則:自定義拷貝構(gòu)造函數(shù),必然要實現(xiàn)深拷貝!
4.3 拷貝構(gòu)造函數(shù)的調(diào)用時機(jī)
什么時候調(diào)用拷貝構(gòu)造函數(shù)?
4.4 繼承關(guān)系中的拷貝構(gòu)造函數(shù)
假設(shè)B繼承自A,如下代碼:
B b1; B b2(b1); // 先調(diào)用A類的構(gòu)造函數(shù),再調(diào)用B類的拷貝構(gòu)造函數(shù)5 賦值構(gòu)造函數(shù)
5.1 合成的賦值構(gòu)造函數(shù)
如果沒有定義賦值構(gòu)造函數(shù),編譯器會自動定義“合成的賦值構(gòu)造函數(shù)”,與其他合成的構(gòu)造函數(shù)相同,是“淺拷貝”(又稱為“位拷貝”)。
5.2 自定義的賦值構(gòu)造函數(shù)
簡要的賦值構(gòu)造函數(shù)代碼如下:
Human& Human::operator=(const Human &man) {cout << "調(diào)用" << __FUNCTION__ << endl;if (this == &man) {return *this; //檢測是不是對自己賦值:比如 h1 = h1;}// 如果有必要,需要先釋放自己的資源(動態(tài)內(nèi)存)//delete[] addr;//addr = new char[ADDR_LEN];// 深拷貝strcpy_s(addr, ADDR_LEN, other.addr);// 處理其他數(shù)據(jù)成員name = man.name;age = man.age;salary = man.salary;// 返回該對象本身的引用, 以便做鏈?zhǔn)竭B續(xù)處理,比如 a = b = c;return *this; }6 在已經(jīng)申請的空間上調(diào)用構(gòu)造函數(shù)
這真是一個騷操作,很多情況下我們需要為對象預(yù)先分配空間,但是如果對象沒有默認(rèn)的構(gòu)造函數(shù)就會很尷尬。我們可以通過malloc分配空間,然后在需要的時間再在這片空間上調(diào)用指定的構(gòu)造函數(shù)。示例代碼如下:
#include <iostream> #include <vector> #include <cstdlib>using namespace std;class Test39 { private:int age; public:Test39(){cout << "Test39()" << endl;}~Test39(){cout << "~Test39()" << endl;} };void test39() {Test39* p = (Test39*)malloc(sizeof(Test39));new (p) Test39();p->~Test39(); }不得不說C++真的是騷,真的足夠強(qiáng)大,真的讓我學(xué)不會!越學(xué)不會我越喜歡,不信搞不定C++。
參考資料:
總結(jié)
- 上一篇: C#中类的属性(Property)
- 下一篇: 定点数的编码表示方法