多態: 將派生類對象視爲基類對象,執行派生類對象的操作, 可用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. 當派生類對象被視爲基類對象時(派生類類型轉成基類類型),雖然類型被轉變,但虛函數表指針(地址)並沒有發生改變,仍然是派生類的虛函數指針,所有在調用基類的函數時,會調用派生類的虛函數實現。