1. 程式人生 > 其它 >c++學習筆記------繼承與多型5

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, 在呼叫解構函式時發生動態繫結,能夠呼叫派生類的解構函式,避免派生類物件無法析構,造成記憶體洩漏。