第三十四節 C++ 多態原理與虛函數表

多態: 將派生類對象視爲基類對象,執行派生類對象的操作, 可用virtual實現多態。

下面代碼存在兩個問題:

#include <iostream>
using namespace std;

/* 這段代碼將存在兩個嚴重問題:
 * 1. 當在函數VerityWhitchClass()傳入一個對象時,我們希望它執行被傳入對象的方法,但這裏執行了基類的方法
 * 2. 當delete傳入的對象指針時, 應該將先釋放子類對象,再釋放基類對象,這裏僅僅釋放了基類對象,造成了內存泄漏
 */
class BaseClass {
public:
	void debugFun() { cout << "this is BaseCalss" << endl; }
	BaseClass() { cout << "BaseClass constructor" << endl; }
	~BaseClass() { cout << "~BaseClass deconstructor" << endl; }
};

/*實例化對象時,將創建兩個對象,子對象和基類對象,通過從調用的構造函數可以看出*/
class SonClass : public BaseClass {
public:
	void debugFun() { cout << "this is SonClass" << endl; }
	SonClass() { cout << "SonClass constructor" << endl; }
	~SonClass() { cout << "~SonClass deconstructor" << endl; }
};

/*這裏採用了指針傳入(也可以採用引用方式),而沒有采用值傳入的方式,爲了防止出現淺複製*/
void VerityWhitchClass(BaseClass* Base) {//子類實例化對象當參數,這裏將子類對象轉化成基類類型
	Base->debugFun();  //問題1: 應該調用傳入對象的方法,但這裏調用了基類的方法,
	delete Base; //問題2: 應該先釋放子類對象,再釋放基類對象,但這裏僅釋放了基類對象
}

int main()
{
	SonClass* Son = new SonClass; //堆上實例化對象,需要用delete去釋放
	VerityWhitchClass(Son);
	return 0;
}

output:

BaseClass constructor
SonClass constructor
this is BaseCalss             //錯誤,調用了基類的方法,沒有調用派生類的方法

~BaseClass deconstructor   //錯誤,只對基類對象進行析構,沒有對派生類對象進行析構

------------------------------------------------------------------------------------

這裏將解決上面的問題,也就是實現多態。

#include <iostream>
using namespace std;

class BaseClass {
public:
	/*用關鍵字virtual將函數聲明爲虛函數*/
	virtual void debugFun() { cout << "this is BaseCalss" << endl; }
	BaseClass() { cout << "BaseClass constructor" << endl; }
	/*用關鍵字virtual將函數聲明爲虛析構函數*/
	virtual ~BaseClass() { cout << "~BaseClass deconstructor" << endl; }
};

/*實例化對象時,將創建兩個對象,子對象和基類對象,通過從調用的構造函數可以看出*/
class SonClass : public BaseClass {
public:
	void debugFun() { cout << "this is SonClass" << endl; }
	SonClass() { cout << "SonClass constructor" << endl; }
	~SonClass() { cout << "~SonClass deconstructor" << endl; }
};


void VerityWhitchClass(BaseClass* Base) {
	Base->debugFun();
	delete Base; 
}

int main()
{
	SonClass* Son = new SonClass; //堆上實例化對象,需要用delete去釋放
	VerityWhitchClass(Son);
	return 0;
}

output: 

BaseClass constructor
SonClass constructor
this is SonClass     //調用正確,調用了派生類對象的方法
~SonClass deconstructor //析構了兩個對象

~BaseClass deconstructor

---------------------------------------------------------------------------------

多態的原理:在實例化含有虛函數的類時,會在對象中產生一個虛函數表指針(通過打印對象的大小可以看出多了4byte)。

這個指針指向虛函數表,虛函數表中存放着虛函數的地址,每個虛函數均指向函數實現。

1. 對於基類:虛函數指向基類的虛函數實現。

2. 對於派生類:虛函數指向派生類的虛函數實現,若繼承來的虛函數,沒有在派生類中實現,指向基類的虛函數實現。

3. 當派生類對象被視爲基類對象時(派生類類型轉成基類類型),雖然類型被轉變,但虛函數表指針(地址)並沒有發生改變,仍然是派生類的虛函數指針,所有在調用基類的函數時,會調用派生類的虛函數實現。


發佈了69 篇原創文章 · 獲贊 73 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章