《深度探索C++對象模型》調用虛函數

若是一個類有虛函數,那麼這個類的虛函數會被放在一個虛函數表裏面, 使用這個類聲明的對象中,會有一個指向虛函數表的指針,當使用指向 這個對象的指針或者這個對象的引用調用一個虛函數的時候,就會從虛函數表中去 查找該函數,而後對其進行調用。函數

若是有以下的類:佈局

class A {
    public :
        int m_a;
        A() {}
        ~A() {}

        virtual void test() { cout << "A info : " << __LINE__ << " , " << __func__ << endl;}
};

class B : public A{
    public :
        int m_b;
        B() {}
        ~B() {}

        virtual void test() { cout << "B info : " << __LINE__ << " , " << __func__ << endl;}
};

 

那麼咱們顯示出一個 B 類對象的內存狀態, 這個類聲明的對象的內存佈局會是下面這樣:spa

#ifdef __x86_64__
cout << "__x86_64__" << endl;
#else 
cout << "not 64" << endl;
#endif

cout << "sizeof(B) = " << sizeof(B) << endl;
cout << "sizeof(int) = " << sizeof(int) << endl;

B b;
b.m_a = 0x01010101;
b.m_b = 0x02020202;

show_mem(&b, sizeof(b));

 

執行結果:指針

__x86_64__
sizeof(B) = 16
sizeof(int) = 4
addrress      : 00 f8 cc fa ff 7f 00 00 
memory layout : 00 0f 40 00 00 00 00 00 01 01 01 01 02 02 02 02

咱們看到,擁有兩個 int 成員變量的 b 對象,它佔用的內存大小卻不是 兩個 sizeof(int) 的和 8,而是16。很明顯,另外8個字節就是存放虛函數表地址 的了,由於目前使用的是64位系統,指針佔用的空間是64 bit。code

那麼,咱們如今知道了一個對象的內存佈局後,就能夠採起 "非法" 手段 調用一個虛函數了。好比下面這段代碼:對象

#ifdef __x86_64__ 
typedef unsigned long int  POINT_SIZE;
#else
typedef int POINT_SIZE;
#endif

typedef void(*Fun)();

//獲取對象的地址
POINT_SIZE *po = (POINT_SIZE *)&b;

//獲取這個對象前 8 個字節的值,這個值是虛函數表的地址
POINT_SIZE tbl = po[0];

//把這個值轉換爲地址類型,也就是虛函數表的地址
POINT_SIZE *ptbl = (POINT_SIZE *)tbl;

int pos = 0;
//虛函數表的第一表項就是第一個虛函數的函數地址,
//這裏將其轉換爲函數類型
Fun pfun = (Fun)(ptbl[pos]);

//調用這個函數
pfun();

 

調用的結果是:blog

B info : 38 , test

 

說明調用了 B 類的虛函數,內存佈局以下:內存

這樣,咱們使用很是規手段就能夠調用一個類的虛函數了。get


同步發表:http://www.fengbohello.top/book/b/1275同步

相關文章
相關標籤/搜索