c++學習筆記------繼承與多型5
C++繼承與多型(5)
虛解構函式
一. 兩個問題:
-
問題一: 哪些函式不能實現成虛擬函式?
首先要認識虛擬函式的依賴:
1.虛擬函式能產生地址,儲存在vftable當中
2.物件必須存在(vfptr->vftable->虛擬函式地址,而vfptr儲存在物件的記憶體空間中)根據虛擬函式的依賴條件可以分析得出:
1.建構函式
(1) virtual+建構函式(不可以)
(2) 建構函式中(呼叫的任何函式,都是靜態繫結的)呼叫虛擬函式,也不會發生靜態繫結 (3) 派生類物件的構造過程,先呼叫的是基類的建構函式,然後才呼叫派生類的建構函式
2.static靜態成員方法
靜態成員方法不依賴物件 -
問題二: 關於虛解構函式, 什麼時候基類的解構函式必須實現成虛擬函式?
解答:基類的指標(引用)指向堆上new出來的派生類物件的時候, delete pb(基類的指標),
它呼叫解構函式的時候,必須發生動態繫結,否則會導致派生類的解構函式無法呼叫舉個例子分析一下問題二
簡單定義基類Base和其派生類Derive
class Base { public: Base(int data = 10) :ma(data) { cout << "Base(int data = 10)" << endl; } void show() { cout << "Base::show()" << endl; } ~Base() { cout << "~Base()" << endl; } protected: int ma; }; class Derive : public Base { public: Derive(int data = 20) :Base(data), mb(data) { cout << "Derive(int data = 20)" << endl; } virtual void show() { cout << "Derive::show()" << endl; } // 基類的解構函式是虛擬函式,那麼派生類的解構函式自動成為虛擬函式 ~Derive() { cout << "~Derive()" << endl; } private: int mb; };
主函式部分
int main() { Base* pb = new Derive(10); pb->show(); delete pb; // 派生類的解構函式沒有呼叫 }
-
case1: 基類Base的解構函式不是虛擬函式時
由以上結果可知,派生類的解構函式沒有呼叫, 這是因為delete需要先呼叫解構函式(釋放外部佔用的記憶體資源(如果需要的話)),然後才會釋放記憶體(free), 而呼叫解構函式pb->~Base() , 找到的是基類的解構函式,發生的是靜態繫結。
-
case2: 基類Base的解構函式是虛擬函式時
由以上結果可知,delete呼叫pb->~Base()時發生了動態繫結,pb獲得了派生類物件空間前四個位元組的值(即vfptr,指向派生類的虛擬函式表),利用vfptr訪問派生類的虛擬函式表,所以呼叫的也是派生類的解構函式
以上例子很好說明當基類的指標pb指向一個new出來的派生類的物件時,基類的解構函式必須寫成虛擬函式確保delete pb, 在呼叫解構函式時發生動態繫結,能夠呼叫派生類的解構函式,避免派生類物件無法析構,造成記憶體洩漏。
-