C++物件記憶體模型2 (虛擬函式,虛指標,虛擬函式表)
阿新 • • 發佈:2018-11-04
C++物件記憶體模型2 (虛擬函式,虛指標,虛擬函式表)
從例子入手,考察如下帶有虛擬函式的類的物件記憶體模型:
class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1(); void func2(); virtual ~A(); private: int m_data1, m_data2; }; class B : A { public: virtual void vfunc1();; void func2(); virtual ~B(); private: int m_data3; }; class C : B { public: virtual void vfunc1(); void func(); private: int m_data1, m_data4; };
注:在子類中出現與父類相同名稱的變數和非虛擬函式不是最佳實踐,這裡是為了說明其記憶體結構。
其物件記憶體結構見下圖。
*圖片來源於侯捷老師
對其分析如下:
1. 每個含有虛擬函式的類在記憶體中多一根指標(vptr),見圖中a,b,c物件中第一個位置,儲存的是虛擬函式表(vtbl)所在的位置。
2. 虛擬函式表(vtbl)儲存著所有虛擬函式的位置,由於其動態繫結特性,在覆寫(override)後在子類中儲存的虛擬函式位置與父類中不相同。
3. 分析上述程式碼, B繼承A,所以A中的資料部分也被B繼承下來,同時B新增上了自己的資料部分m_data3,加之vptr,組成了B左側的記憶體佈局。
A中的虛擬函式vfunc1(),vfunc2()可以被覆寫和動態繫結。
所以在B中,vfunc1()被覆寫,其vtbl中對應項指向了新的函式的位置(亮藍色)。vfunc2()未被覆寫,仍然指向原先位置(深藍色)。
C與B同理,vfunc1()被覆寫,其vtbl中對應項指向了新的函式的位置(橘黃色)。vfunc2()未被覆寫,仍然指向原先位置(深藍色)。
非虛擬函式靜態繫結,儲存在單獨的記憶體空間(code memory section,灰色函式部分),呼叫時把物件的this指標,傳給一個invisible引數,以便確定誰在呼叫函式。
4. 呼叫虛擬函式的語句的C語言形式如圖中下部分所示,其中n表示對應的函式在第幾個位置(編譯器在建立虛擬函式表的時候已知),從而實現動態繫結。