多態是C++面向對象程序設計的一個重要特性。以前看到虛函數覺得很神奇,為什么就能實現多態了呢。最初的時候曾設想,要實現運行時多態,應該讓對象的某個部分始終指向一個固定的地址,子類繼承的時候,就修改這個地址的內容。這樣,父類和子類都是到同一個固定地址去讀取內容,在運行時就能表現不同行為。
在看了《深度探索c++對象模型》之后,發現思路是類似的。在對象中,有一個指針指向一張虛函數表,里面按照次序存放了每一個虛函數,當子類繼承的時候,即到虛函數表的指定位置去修改函數地址。當我們通過父類指針來操作一個子類的時候,調用虛函數,都是通過虛函數表+固定的偏移,這樣運行期多態便實現了。
在深度《深度》這本書中,虛函數表大多放在了對象的末端,不知道現在的編譯器是什么樣的,因此本文就來實際做個實驗測試一下。
實驗環境:VC2013 Express
代碼如下:
class Parent {public: int parent; Parent() : parent(10) {} virtual void a() { cout << "Parent::a()" << endl; } virtual void b() { cout << "Parent::b()" << endl; } virtual void c() { cout << "Parent::c()" << endl; }};class Child : public Parent {public: int child; Child() :child(100) {} virtual void a() { cout << "Child::a()" << endl; } virtual void b_child() { cout << "Child::b_child()" << endl; } virtual void c_child() { cout << "Child::c_child()" << endl; }};class GrandChild : public Child{public: int grandchild; GrandChild() :grandchild(1000) {} virtual void a() { cout << "GrandChild::a()" << endl; } virtual void b_child() { cout << "GrandChild::b_child()" << endl; } virtual void c_grandchild() { cout << "GrandChild::c_grandchild()" << endl; }};int main(){ typedef void(*func)(); GrandChild grandchild; int **vtable = (int **)&grandchild; for (int i = 0; (func)vtable[0][i] != nullptr; i++) { auto pfunc = (func)vtable[0][i]; cout << " ["<<i<<"] "; pfunc(); } return 0;}
結果顯示如下圖所示:
確實,虛函數表指針在對象起始處,并看到了對應項被覆蓋。
新聞熱點
疑難解答
圖片精選