C++類四大隱藏函式詳解(建構函式、解構函式、拷貝構造、賦值函式)
建構函式傳送門
一、解構函式
1、什麼是解構函式
與建構函式一樣也是一種特殊的成員函式,它會在物件釋放的時候自動呼叫,負責一些收尾工作,如:儲存資料、釋放資源等。
2、函式格式
~類名(void)
{
}
3、解構函式的任務
負責釋放在建構函式中獲取到的所有資源。
執行過程:
1、先執行解構函式本身程式碼
2、呼叫成員變數的解構函式
3、呼叫父類的解構函式
- 注意:解構函式與建構函式的執行順序剛好相反
#include <iostream>
using namespace std;
class Test
{
public:
Test(void)
{
cout<<"我是建構函式"<<endl;
}
~Test(void)
{
cout<<"我是解構函式"<<endl;
}
};
void func(void)
{
Test* t = new Test;
cout<<"-------"<<endl;
delete t;
}
int main(int argc,const char* argv[])
{
int n=3;
while(n-- )
func();
}
二、預設的解構函式,建構函式
1、 定義
在設計一個類時,如果沒有顯示實現建構函式與解構函式,編譯器 會自動生成它們,也叫預設的構造和解構函式。
但生成的並不是真正語法意義上的函式,而是功能意義上的函式。
編譯器做為可執行指令的生成著,它有能力直接生成某些功能的二進位制指令,不需要藉助語言上的函式完成某些任務。
2、 什麼時候需要顯示實現建構函式
- 有成員需要初始化
- 需要一些引數做一些準備工作
- 需要在物件使用之前準備一些資源.如:申請一些堆記憶體
3.、什麼時候需要顯示實現解構函式
預設的解構函式會自動釋放編譯器能看得到的所有資源。如:成員變數,類成員,父類
- 儲存一些資料
- 成員變數中有指標,且指向堆記憶體。
三、類物件 建立過程與釋放記憶體總結
建立:
分配記憶體 -> 父類構造 -> 成員構造 -> 自己的構造(初始化成員,申請準備記憶體等)
父類構造:按照繼承表的順序從左到右依次執行父類建構函式
成員構造:按照成員的宣告順序,從上到下依次執行成員變數的建構函式
釋放:
自己的解構函式(儲存資料,釋放堆記憶體等) -> 成員析構 -> 父類的析構 -> 釋放記憶體(物件)
成員析構:按照宣告的順序,從下到上依次執行成員變數的解構函式
父類析構:按照繼承表從右到左依次執行父類的解構函式。
四、拷貝建構函式(賦值構造)
什麼是拷貝建構函式
是一種特殊的建構函式,當使用一個物件初始化另一個新的物件時,就會呼叫隱藏的拷貝建構函式,它也是類自帶建構函式之一,由編譯器自動生成。
拷貝構造格式
類名(const 類名& 變數名)
{
}
呼叫拷貝構造
- 類名 物件 = 物件
- 使用物件作為函式的引數時(不使用引用)
拷貝構造的任務
負責把舊的類物件中的成員拷貝給新的物件(預設,淺拷貝)。
什麼時候顯式使用拷貝構造?
當類中有成員是指標,且該指標指向了一塊堆記憶體,此時拷貝構造應該拷貝指標所指向的記憶體(深拷貝),而預設的淺拷貝只拷貝指標變數的值,這時候會導致指標指向的記憶體被delete從而記憶體崩潰,因此應該顯示地拷貝構造。
#include <iostream>
using namespace std;
class Test
{
int num;
public:
Test(int num)
{
this->num = num;
}
Test(Test& t)
{
num = t.num;
cout << "我是拷貝構造" << endl;
}
void show(void)
{
cout << num << endl;
}
};
void func(Test t)
{
cout << __func__ << endl;
}
int main(int argc,const char* argv[])
{
Test t(100);
Test t1 = t; // 呼叫拷貝構造
t.show();
t1.show();
func(t);
}
七、賦值函式(賦值運算子)
什麼是賦值函式
在C++中是把運算子當做函式處理的,當一個物件給另一個物件賦值時就會自動呼叫該函式
賦值函式格式
類& operator=(const 類& that)
{
}
#include <iostream>
using namespace std;
class Test
{
int num;
public:
Test(int num)
{
this->num = num;
}
void show(void)
{
cout << num << endl;
}
Test& operator=(const Test& that)
{
num = that.num;
cout << "我是賦值函式" << endl;
return *this;
}
};
int main(int argc,const char* argv[])
{
Test t(100);
Test t1(0);
(t1 = t).show(); //呼叫賦值函式
}
什麼時候呼叫
物件 = 物件;
賦值函式的任務
與拷貝建構函式一樣,負責把一個物件的記憶體拷貝給另一個物件(淺拷貝)。
什麼時候顯式實現賦值函式:
當需要顯式實現拷貝構造時,就應該顯示實現賦值函式。