“多型”的關鍵在於通過基礎類別指標或參照呼叫一個虛擬函式時,編譯時不確定到底呼叫的是基礎類別還是派生類的函數,執行時才確定。這是如何實現的呢?
請看下面的程式,該程式演示了多型類物件儲存空間的大小。
#include <iostream>
using namespace std;
class A
{
public:
int i;
virtual void func() {}
virtual void func2() {}
};
class B : public A
{
int j;
void func() {}
};
int main()
{
cout << sizeof(A) << ", " << sizeof(B); //輸出 8,12
return 0;
}
在 32 位編譯模式下,程式的執行結果是:
8, 12
如果將程式中的 virtual 關鍵字去掉,輸出結果變為:
4, 8
對比發現,有了虛擬函式以後,物件所佔用的儲存空間比沒有虛擬函式時多了 4 個位元組。實際上,任何有虛擬函式的類及其派生類的物件都包含這多出來的 4 個位元組,這 4 個位元組就是實現多型的關鍵——它位於物件儲存空間的最前端,其中存放的是虛擬函式表的地址。
每一個有虛擬函式的類(或有虛擬函式的類的派生類)都有一個虛擬函式表,該類的任何物件中都放著該虛擬函式表的指標(可以認為這是由編譯器自動新增到建構函式中的指令完成的)。
虛擬函式表是編譯器生成的,程式執行時被載入記憶體。一個類的虛擬函式表中列出了該類的全部虛擬函式地址。例如,在上面的程式中,類 A 物件的儲存空間以及虛擬函式表(假定類 A 還有其他虛擬函式)如圖 1 所示。
圖1:類A物件的儲存空間以及虛擬函式表