若是一個類有虛函數,那麼這個類的虛函數會被放在一個虛函數表裏面, 使用這個類聲明的對象中,會有一個指向虛函數表的指針,當使用指向 這個對象的指針或者這個對象的引用調用一個虛函數的時候,就會從虛函數表中去 查找該函數,而後對其進行調用。函數
若是有以下的類:佈局
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