C++專題總結之理解虛擬函數、多繼承、虛基類和RTTI

主題 概要
C++ 虛擬函數、多繼承、虛基類、RTTI
編輯 時間
新建 20170102
序號 參考資料
1 More effective C++
2 http://blog.csdn.net/haoel/article/details/1948051

虛擬函數

記得以前面試的時候,面試官問了個問題,“多態的本質是什麼”?
當時沒答上來,現在想想如果能說出虛擬函數表來應該就可以了。
所謂虛函數的“虛”是指“直到運行時才能知道要調用的是哪一個函數”。那通過什麼方法確定?答案是虛函數表和虛函數表指針。virtual table和virtual table pointers通常被分別地稱爲vtbl和vptr。
一個vtbl通常是一個函數指針數組。在程序中的每個類只要聲明瞭虛函數或繼承了虛函數,它就有自己的vtbl,並且類中vtbl的項目是指向虛函數實現體的指針。
例如這個類:

class C1 
{
public:
    C1();
    virtual ~C1();
    virtual void f1();
    virtual int f2(char c) const;
    virtual void f3(const string& s);
    void f4() const;    
};

虛函數表數組,看起來像這樣:

這裏寫圖片描述
注意非虛函數f4不在表中,而且C1的構造函數也不在。
如果有一個C2類繼承自C1,重新定義了它繼承的一些虛函數,並加入了它自己的一些虛函數:

class C2 : public C1 
{
public:
    C2();               // 非虛函數
    virtual ~C2();     // 重定義函數
    virtual void f1();  // 重定義函數
    virtual void f5(char *str); // 新的虛函數
};

它的virtual table項目指向與對象相適合的函數。這些項目包括指向沒有被C2重定義的C1虛函數的指針,而f1被替換爲子類重定義的指針:

這裏寫圖片描述
如果有一函數調用:
ptr->f1();
根據這個虛函數表就能確定要執行哪個函數了。
實際上根據虛函數表只是完成了一半的工作,假設新建一個對象時,怎麼樣確定這個對象是使用哪一個虛函數表?只有用某種方法指出每個對象對應的vtbl(虛函數表)時,它們才能使用。這是virtual table pointer的工作,它來建立這種聯繫。
每個聲明瞭虛函數的對象都帶有它,它是一個看不見的數據成員,指向對應類的virtual table。
我們可以認爲包含有虛函數的對象的佈局是這樣的:

這裏寫圖片描述
假如我們有一個程序,包含幾個C1和C2對象。對象、vptr和剛纔我們講述的vtbl之間的關係,在程序裏我們可以這樣去想象:

這裏寫圖片描述

考慮這段這段程序代碼:

void makeACall(C1 *pC1)
{
    pC1->f1();
}

通過指針pC1調用虛擬函數f1。僅僅看這段代碼,你不會知道它調用的是那一個f1函數——C1::f1或C2::f1,因爲pC1可以指向C1對象也可以指向C2對象。儘管如此編譯器仍然得爲在makeACall的f1函數的調用生成代碼,它必須確保無論pC1指向什麼對象,函數的調用必須正確。編譯器生成的代碼會做如下這些事情:
1). 通過對象的vptr找到類的vtbl。
2). 找到對應vtbl內的指向被調用函數的指針。
3). 調用第二步找到的的指針所指向的函數。

多繼承與虛基類

多繼承經常導致對虛基類的需求。沒有虛基類,如果一個派生類有一個以上從基類的繼承路徑,基類的數據成員被複制到每一個繼承類對象裏,繼承類與基類間的每條路徑都有一個拷貝。而把基類定義爲虛基類則可以消除這種複製。

虛基類是以什麼方式消除這種複製的?

虛基類的實現經常使用指向虛基類的指針做爲避免複製的手段。
例如考慮下面這幅圖,我經常稱它爲“恐怖的多繼承菱形”:

這裏寫圖片描述
這裏A是一個虛基類,因爲B和C虛擬繼承了它。使用一些編譯器(特別是比較老的編譯器),D對象會產生這樣佈局:
這裏寫圖片描述
可以看到,通過虛繼承的B類和C類中,分別有一個指向基類數據成員的指針,這樣就避免了重複複製的問題。

運行時類型識別

RTTI能讓我們在運行時找到對象和類的有關信息,所以肯定有某個地方存儲了這些信息讓我們查詢。這些信息被存儲在類型爲type_info的對象裏,你能通過使用typeid操作符訪問一個類的type_info對象。

語言規範上這樣描述:我們保證可以獲得一個對象動態類型信息,如果該類型有至少一個虛函數。

一點思考:運用C++也不短時間了,這個知識感覺還是盲點,是類似JAVA/C#裏面反射的東西嗎?

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