1.構造函數
構造函數是特殊的成員函數
創建類類型的新對象時,系統會自動調用構造函數
構造函數是爲了保證對象的每個數據成員都被正確初始化
①構造函數的特點
函數名和類名完全相同
不能定義構造函數的類型(返回類型),也不能使用void
通常情況下構造函數應聲明爲公有函數,否則它不能向其他函數那樣顯式地調用
構造函數被聲明爲私有時有特殊的用途
②默認構造函數:不帶參數的構造函數
如果程序中未聲明構造函數,則系統自動產生出一個默認構造函數(如果程序中已經定義了構造函數,則系統不會自動生成默認構造函數,需要手動編寫)
③構造函數的重載
一個類中可以有多個構造函數,編譯器會自動重載
④構造函數與new運算符
定義指針對象時要使用new在堆上進行分配
④全局對象的構造函數先於main函數
2.析構函數
析構函數是程序結束時,系統自動調用用於釋放空間的
析構函數的函數名和類名相似(前面多了一個字符“~”)
析構函數沒有返回類型,也沒有參數
析構函數不能被重載
如果沒有定義析構函數,編譯器會自動生成一個默認析構函數
析構函數是一個空函數
①析構函數與數組
如果想要析構函數釋放數組,必須先用delete釋放數組空間
②析構函數與delete運算符
Delete運算符會引起析構函數的調用
③析構函數的顯式調用
除了系統自動調用,我們也可以在程序中顯式的調用析構函數
注意:析構的順序與構造的順序相反
下面用一個例子來綜合理解上面的幾點
首先,編寫一個Test.h,用於聲明類
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
Test();
Test(int x, int y, int z);
~Test();
private:
int x_;
int y_;
int z_;
protected:
};
#endif
接着,編寫Test.cpp來外部實現構造函數以及析構函數,我們在構造函數和析構函數中增加了一些打印信息,以此來觀察構造和析構的順序
#include "Test.h"
#include <iostream>
using namespace std;
Test::Test()
{
cout << "Default Init" << endl;
}
Test::Test(int x, int y, int z)
{
x_ = x;
y_ = y;
z_ = z;
cout << "Init x = " << x_ << endl;
}
Test::~Test()
{
cout << "Destroy x = " << x_ << endl;
}
最後,編寫main函數,我們在其中定義了兩個對象,一個指針對象,還有一個數組對象,指針必須使用new進行分配,使用delete進行釋放
#include "Test.h"
#include <iostream>
int main()
{
Test t1(1,2,3);
Test t2;
Test *p = new Test(4,5,6);
Test array[3];
delete p;
return 0;
}
現在我們來看一下結果,可以看到構造和析構的順序,發現指針對象的析構先於數組,這是因爲調用了delete釋放指針,delete引起了析構函數的調用,所以先對指針進行了析構,之後按照正常順序進行析構