1. 程式人生 > >C++ 虛擬函式表 存在哪

C++ 虛擬函式表 存在哪

C++通過虛擬函式實現多型。那麼虛擬函式表具體儲存在哪?是每一個物件都有虛擬函式表,還是每一類有虛擬函式表?讓我們通過程式碼分析一下。程式碼執行在Windows平臺,使用Visual Studio2010編譯。

虛擬函式基礎知識

C++中,一個類存在虛擬函式,那麼編譯器就會為這個類生成一個虛擬函式表,在虛擬函式表裡存放的是這個類所有虛擬函式的地址。當生成類物件的時候,編譯器會自動的將類物件的前四個位元組設定為虛表的地址,而這四個位元組就可以看作是一個指向虛擬函式表的指標。虛擬函式表可以看做一個函式指標陣列。

程式碼分析

class Base
{
public:
    virtual
void Hello() { cout << "Base Hello" << endl; } }; class Derived:public Base { public: virtual void Hello() { cout << "Derived Hello" << endl; } }; int main() { //獲取程序基址 HANDLE hBase = GetModuleHandle(NULL); //基類 Base* base = new
Base(); //獲取虛擬函式表地址偏移 DWORD baseVirtualTable = 0; memcpy(&baseVirtualTable, base,sizeof(DWORD)); baseVirtualTable -= (DWORD)hBase; printf("base VirtualTable offset is 0x%08X\n", baseVirtualTable); //派生類 Derived* derived= new Derived(); //獲取虛擬函式表地址偏移 DWORD derivedVirtualTable = 0
; memcpy(&derivedVirtualTable, derived,sizeof(DWORD)); derivedVirtualTable -= (DWORD)hBase; printf("derived VirtualTable is 0x%08X\n",derivedVirtualTable); //基類指標指向子類物件 Base* pBaseToDerived = new Derived(); //獲取虛擬函式表地址偏移 DWORD pBaseToDerivedVirtualTable = 0; memcpy(&pBaseToDerivedVirtualTable, pBaseToDerived,sizeof(DWORD)); pBaseToDerivedVirtualTable -= (DWORD)hBase; printf("pBaseToDerived VirtualTable is 0x%08X\n",pBaseToDerivedVirtualTable); }

程式碼分別打印出,基類物件,子類物件,以及指向子類的基類指標的虛擬函式表相對於程序基址的偏移,結果如下圖

這裡寫圖片描述

這裡可以看出,虛擬函式表是屬於類,類的所有物件共享這個類的虛擬函式表。並且,子類物件與指向子類的基類指標指向的物件,使用同一個虛擬函式表,符合C++的多型要求。

隨後,使用PE工具,開啟程式碼生成的exe檔案,各個Section的偏移地址如下圖

這裡寫圖片描述

剛才虛擬函式表的相對偏移地址為0x000183E8和0x00017834,屬於.rdata段。由此可見,虛擬函式表儲存在程序的只讀資料段。

結論

  1. 虛擬函式表屬於類,類的所有物件共享這個類的虛擬函式表。
  2. 虛擬函式表由編譯器在編譯時生成,儲存在.rdata只讀資料段。