C++面向對象程序設計(六)——多態
本文是中國大學MOOC,北京大學程序設計與算法C++面向對象程序設計第六週筆記。本課程學習的github倉庫歡迎Fork
虛函數和多態
虛函數
類的定義中,前面有virtual
關鍵字的成員函數就是虛函數
class base{
virtual int get();
};
int base::get(){}
virtualenv
關鍵字只用在類定義裏的函數聲明中,寫函數體時不用。
構造函數和靜態成員函數不能是虛函數派生類和基類同名同參數表的函數,不加virtualenv
也自動成爲虛函數
虛函數與普通函數的本質區別是,虛函數可以參加多態,普通函數不可以
多態
作用
增強程序的可擴充性
派生類的指針可以賦給基類指針
通過基類指針調用基類和派生類中的同名虛函數時:
如果該指針指向一個基類對象,那麼被調用是基類的虛函數
如果指向一個派生類對象,那麼被調用的是派生類的虛函數
派生類的對象可以賦給基類引用
通過基類引用調用基類和派生類中同名虛函數時:
如果該引用引用的是一個基類對象,那麼被調用是基類的虛函數
如果引用的是一個派生類對象,那麼被調用的是派生類的虛函數
多態的實現原理
每一個有虛函數的類(或有虛函數的類的派生類)都有一個虛函數表,該類的任何對象中都放着虛函數表的指針。虛函數表中列出了該類的虛函數地址。多出來的字節就是用來放虛函數表的地址的
虛析構函數
通過基類的指針刪除派生類對象時,通常情況下只調用基類的析構函數。但是刪除一個派生類對象時,應該先調用派生類的析構函數,然後調用基類的析構函數。這樣會衝突
所以我們要把基類的析構函數聲明爲virtual
基類的析構函數是虛函數,派生類的析構函數可以不進行聲明virtual
通過基類的指針刪除派生類對象時,首先調用派生類的析構函數,然後調用基類的析構函數。
一般來說,一個類如果定義了虛函數,那麼析構函數也應該定義成虛函數。或者一個類打算作爲基類使用,也應該將析構函數定義成虛函數
但是不允許虛函數作爲構造函數
純虛函數和抽象類
純虛函數
沒有函數體的虛函數
class A{
private:
int a;
public:
virtual void Print() = 0; //純虛函數
void fun(){
cout<<"fun";
}
}
抽象類
包含純虛函數的類叫抽象類,抽象類只能作爲基類來派生新類使用,不能創建抽象類的對象
抽象類的指針和引用可以指向由抽象類派生出來的類的對象
A a; //錯誤,A是抽象類,不能創建對象
A *pa; //可以,可以定義抽象類的指針和引用
pa = new A; //錯誤,A是抽象類,不能創建對象
抽象類的成員函數內可以調用純虛函數,但是在構造函數或析構函數內部不能調用純虛函數
如果一個類從抽象類派生而來,那麼當且僅當它實現了基類中的所有純虛函數,它才能成爲非抽象類