c++的多型分為動態多型和靜態多型,其中靜態多型主要靠過載和模板來實現,而動態多型則主要靠繼承來實現了。
那麼靜態和動態,怎麼算靜,怎麼算動呢?靜態多指編譯期能決定的事情,而動態多指執行時才決定的事情。例如過載,在編譯期生成符號的時候就已經確定不同的函式了,而繼承的重寫(override)則是在執行到具體的**位置確認指標內部的虛函式表指向的函式位址時才知道執行哪個函式,被稱為動態多型。
虛函式表指標指向虛函式表,虛函式表每個類乙個,如果是單繼承的話子類和父類的虛函式表會合體,下面是乙個簡單的例子
class father
};class child : public father
};child c;
father f;
用過偵錯程式檢視變數內部可以看到child類的物件c中有父類的虛函式表指標,但是自己的呢?單純乙個父類物件也有自己的虛函式表指標,為什麼child類的物件自己的虛表指標不見了呢?
那麼乙個猜測就是子類的虛函式表和父類的虛函式表合體了,這個猜測到底正不正確呢?得想個辦法驗證一下!
一般虛表指標存放在物件位址空間的頭4位,這裡先取得上圖中看到的father的vptr指向的虛表,虛表位址的獲取需要獲取虛表指標中存放的值。
cout << hex << "virtual table address: " << *(int *)(&c) << endl;
然後是獲得fatherfunction
函式指標的位址
cout << hex << "fatherfunction address: " << (int *)*(int *)(&c) << endl;
typedef void(*fun)();
child c;
cout << hex << "virtual table address: " << *(int *)(&c) << endl;
cout << hex << "fatherfunction address: " << (int *)*(int *)(&c) << endl;
fun father_func = (fun)*((int *)*(int *)(&c));
fun child_func = (fun)*((int *)*(int *)(&c) + 1);
father_func();
child_func();
得到的結果如下圖所示
ps:簡單解釋一下取函式指標的**
續表為手誤,是虛表。圖不好改就不改了
靜態成員不屬於任何物件,所以就算加上了virtual也沒有意義
靜態函式沒有this指標,虛函式表存在於物件的位址空間,使用物件的this指標訪問,但是靜態函式沒有this指標故也無法訪問虛函式表。
const成員函式要求使用者為const類物件,再換乙個說法就是要求this指標為const,但是靜態函式沒有this指標,故使用const關鍵字修飾靜態函式毫無意義
ps:volatile是乙個關鍵字用來表示當前語句不會被編譯器優化,且要求每次直接讀值
多繼承時,物件內部會有多個虛表指標指向多個虛函式表,如果自己也能繼續繼承,那麼自己的續表會和第乙個虛表合體,虛表合體這個在上面已經描述過了,多個多繼承的話也會合併,是會和記憶體空間的第乙個虛表合併。
class father
};class mother
};class child : public father, public mother
};
把類的繼承關係改成這樣,讓child類繼承自father和mother,此時child的物件c中有幾個虛表指標?
答案是兩個分別是兩個類的虛表指標,此時為了判斷合體,還是用上面提到的方法,也能成功,發現子類的虛表是存在頭4個位元組的虛表指標所指向的虛表內的。
而這個虛表指標的先後順序和宣告繼承的順序一致,public mother
如果在public father
之前的話就會變成如下圖所示
探秘C 仿函式
最近喵哥遇到乙個問題 如何在不借助額外空間 新建vector等 來實現map自己的想法 不只是表面的公升序 降序 排序 sort只適用於順序容器,map並不可以使用 如果忽略 不借助額外空間這個要求 完全可以用乙個vector來實現 include include include include i...
虛指標,虛函式,虛函式表,純虛函式
虛指標 虛繼承 在使用多重繼承時,如存在 class a 有m a變數 class a1 virtual public a,m a1 class a2 virtual public a m a2 class b public a1,public a2 m b 時 存在以下記憶體儲存順序 虛指標 指向...
虛函式 純虛函式
一 定義.純虛函式是在基類中宣告的虛函式,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。在基類中實現純虛函式的方法是在函式原型後加 0 virtual void funtion1 0 二 引入原因 1 為了方便使用多型特性,我們常常需要在基類中定義虛函式。2 在很多情況下,基類本身生成...