一、六大默認成員函數
默認成員函數是用戶沒有顯式實現,編譯器自動生成的成員函數。
一個類,我們在不寫的情況下,編譯器會默認生成六個默認成員函數
本文詳細介紹構造函數和析構函數
二、構造函數
構造函數雖名為構造函數,但是這個函數并不開辟空間創建對象(經常使用的局部對象是棧幀創建的)
構造函數的功能是:在對象實例化時初始化對象,類似于我們以前寫的Init()
函數
CPP引入構造函數,我們也就可以代替Init()
函數了
構造函數的特點:
- 函數值與類名相同
class Info{
public:
// 構造函數Info(){//...}
private:
//...
};
- 無返回值(啥都不需要給,void也不用)
- 對象實例化時(創建對象)系統會自動調用對應的構造函數
- 支持重載,可以根據參數不同定義多個構造函數
- 如果沒有顯式定義構造函數,CPP的編譯器會自動生成一個無參的默認構造函數,一旦顯式定義就不會生成
構造函數的類型
- 默認構造函數
默認構造函數分為無參構造函數、編譯器自動生成的構造函數、全缺省構造函數
這三個函數有且只能存在一個:
而無參構造函數和 全缺省構造函數雖能構成函數重載,但是會產生調用歧義
總結一下: 默認構造函數是不用傳實參的構造函數
class Info {
public:// 無參的默認構造函數Info() {_name = "UnKnow";_age = 0;}void Print() {cout << " 默認構造函數被調用" << endl;cout << _name << " " << _age << endl;}
private:string _name;int _age;
};int main() {Info I1;I1.Print();
}
- 帶參數的構造函數
class Info {
public:// 帶參的構造函數Info(string name, int age) {_name = name;_age = age;}void Print() {cout << " 默認構造函數被調用" << endl;cout << _name << " " << _age << endl;}
private:string _name;int _age;
};int main() {// 調用帶參數的構造函數Info I2("kunkun", 18);I2.Print();
}
編譯器自動生成的默認構造函數深度剖析
我們如果沒有顯式定義構造函數,編譯器自動生成的構造函數會將對象初始化成什么呢?
類型的分類:
-
內置類型:沒有規定要處理(可處理可不處理,看編譯器類型)
-
自定義類型:調用自定義類型對象的默認構造函數,本質是不斷套娃,深挖!!!
分析一下:
D1這個對象中有三個內置類型成員變量和一個自定義類型成員變量,不寫構造函數,首先自動生成
Date()
的默認構造函數,到private
中發現三個內置類型,則不做處理,有個自定義類型_t
,則去調用Time()
的構造函數,發現有構造函數,則按照構造函數初始化命令初始化,如果Time()
沒有構造函數呢?那么_hour _minute _second
也是內置類型,不做處理
注意:沒有默認構造函數會報錯
三、析構函數
析構函數與構造函數功能相反,析構函數不是銷毀對象,比如局部對象存在棧中,函數棧幀結束就自動銷毀釋放內存。
析構函數的功能是在對象銷毀時完成對象中資源的清理釋放
析構函數的功能類似于Destroy()
,析構函數就可以完美替代Destroy()
了
析構函數的特點
- 無參數無返回值,與構造函數類似
- 函數名與類名相同,在類名前加字符 “~” eg:
Name()
- 一個類只能有一個析構函數,所以析構函數不能重載如果沒有顯式定義,系統會自動生成默認的析構函數
- 對象生命周期結束,會自動調用析構函數
- 與構造函數相同,編譯器自動生成的析構函數對內置類型不做處理,對自定義類型則會調用它的析構函數
注意:我們顯式寫析構函數,自定義類型成員會調用它的析構函數,換句話說,自定義類型成員無論什么情況下都會調用析構函數
析構函數的語法
class Test {
public:Test() {cout << "構造函數調用成功" << endl;}~Test() {cout << "析構函數調用成功" << endl;}
private:
};int main() {cout << "程序開始運行" << endl;{Test T;// 構造函數被調用}// T生命周期結束cout << "程序運行結束";
}
總結:
- 有資源需要手動清理,需要寫析構函數
- 有兩種場景不需要寫析構函數,利用默認生成的即可:
- 沒有資源需要清理,例如:
Date()
日期列表全是局部成員 - 內置類型沒有資源需要清理,剩下的全是自定義類型成員,且這些類有正確的析構函數 eg:
- 沒有資源需要清理,例如:
public:Engine() { std::cout << "Engine created.\n"; }~Engine() { std::cout << "Engine destroyed.\n"; }
};class Car {
public:Engine engine;int speed;
}; // Car的析構函數不需要手寫