程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++ 虛函數表解析

c++ 虛函數表解析

編輯:C++入門知識

c++ 虛函數表解析


對C++ 了解的人都應該知道虛函數(Virtual Function)是通過一張虛函數表(Virtual Table)來實現的。簡稱為V-Table。在這個表中,主是要一個類的虛函數的地址表,這張表解決了繼承、覆蓋的問題,保證其內容真實反應實際的函數。這樣,在有虛函數的類的實例中這個表被分配在了這個實例的內存中,所以,當我們用父類的指針來操作一個子類的時候,這張虛函數表就顯得由為重要了,它就像一個地圖一樣,指明了實際所應該調用的函數。     這裡我們著重看一下這張虛函數表。C++的編譯器應該是保證虛函數表的指針存在於對象實例中最前面的位置(這是為了保證取到虛函數表的有最高的性能——如果有多層繼承或是多重繼承的情況下)。 這意味著我們通過對象實例的地址得到這張虛函數表,然後就可以遍歷其中函數指針,並調用相應的函數。     可以將虛函數表看做一個二維數組,其中每個一維數組的首地址存儲在對象的實例之中。      來看個例子,通過實例得到虛函數表地址,進而訪問虛函數。       /* version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */   #include "stdafx.h" #include <iostream> using namespace std;   class Base1 { public:     Base1()     {     }       virtual void f()     {         cout << "Base1::f" << endl;     }     virtual void g()     {         cout << "Base1::g" << endl;     }     virtual void h()     {         cout << "Base1::h" << endl;     } };   typedef void(*Fun)(void);   void test() {     Base1 obj;     Fun pFun;     int **pVtab = (int **)(&obj);       // base1     pFun = (Fun)pVtab[0][0];     pFun();       pFun = (Fun)pVtab[0][1];     pFun();       pFun = (Fun)pVtab[0][2];     pFun(); }   int main() {     test();     return 0; } /* Base1::f Base1::g Base1::h */ 圖解如下         在上面這個圖中,虛函數表的最後多加了一個結點,這是虛函數表的結束結點,就像字符串的結束符“/0”一樣,其標志了虛函數表的結束。這個結束標志的值在不同的編譯器下是不同的。   下面,將分別說明“無覆蓋”和“有覆蓋”時的虛函數表的樣子。沒有覆蓋父類的虛函數是毫無意義的。之所以要講述沒有覆蓋的情況,主要目的是為了給一個對比。在比較之下,我們可以更加清楚地知道其內部的具體實現。   (1)一般繼承(無虛函數覆蓋) 下面,再讓我們來看看繼承時的虛函數表是什麼樣的。假設有如下所示的一個繼承關系:       請注意,在這個繼承關系中,子類沒有重載任何父類的函數。那麼,在派生類的實例中,其虛函數表如下所示:   對於實例:Derive d; 的虛函數表如下:       我們可以看到下面幾點:   1)虛函數按照其聲明順序放於表中。   2)父類的虛函數在子類的虛函數前面。   代碼驗證如下     /* version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */   #include "stdafx.h" #include <iostream> using namespace std;   class Base1 { public:     Base1()     {     }       virtual void f()     {         cout << "Base1::f" << endl;     }     virtual void g()     {         cout << "Base1::g" << endl;     }     virtual void h()     {         cout << "Base1::h" << endl;     } };   class Derived: public Base1 {     virtual void f1()     {         cout << "Derived::f1" << endl;     }     virtual void g1()     {         cout << "Derived::g1" << endl;     }     virtual void h1()     {         cout << "Derived::h1" << endl;     }   };   typedef void(*Fun)(void);   void test() {     Derived obj;     Fun pFun;     int **pVtab = (int **)(&obj);       // base1     pFun = (Fun)pVtab[0][0];     pFun();       pFun = (Fun)pVtab[0][1];     pFun();       pFun = (Fun)pVtab[0][2];     pFun();       // derived     pFun = (Fun)pVtab[0][3];     pFun();       pFun = (Fun)pVtab[0][4];     pFun();       pFun = (Fun)pVtab[0][5];     pFun(); }   int main() {     test();     return 0; } /* Base1::f Base1::g Base1::h Derived::f1 Derived::g1 Derived::h1 */

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved