需要實現多態必不可少的就是虛函數,類的成員函數前加virtual關鍵字,這個成員函數就是虛函數;例如:
class T{ public: virtual void fun() { cout<<"fun()"<<endl; } int _t;};在不加virtual的情況下:sizeof(T)的大小為4;加了vitual變成虛函數之后:sizeof(T)的大小為8;這是為什么呢?? 存在虛函數的類的對象模型為:
由此圖可以看出T的對象中不僅有_t而且還有一個指針,這個指針指向的是一個存放虛函數地址的表,也就是虛表。所以在類成員函數前加了virtual之后的大小為8;根據下圖就可以看出虛表中是怎么去存放虛函數的地址:
在單繼承下的虛函數表又是什么樣??
class T{public: virtual void fun1() { cout << "T::fun1()" << endl; } virtual void fun2() { cout << "T::fun1()" << endl; } int _t;};class Z : public T{public: virtual void fun1() { cout << "Z::fun1" << endl; } virtual void fun3() { cout << "Z::fun3" << endl; } int _z;};上述代碼中,類Z單繼承T,重寫了T類中的fun1,fun2并沒有重寫,在Z類本身中還加了自己的虛函數fun3;Z的對象模型為:
vs2013監視窗口:

由上圖監視窗口可以看出在__vfPtr所指的虛表中只有Z::fun1和T::fun2這兩個虛函數的地址,fun3并沒有存在于虛表中,這是因為vs2013下編譯器的一個bug,不過我們換一種方式(打印虛表)來看虛表:
class T{public: virtual void fun1() { cout << "T::fun1()" << endl; } virtual void fun2() { cout << "T::fun1()" << endl; } int _t;};class Z : public T{public: virtual void fun1() { cout << "Z::fun1()" << endl; } virtual void fun3() { cout << "Z::fun3()" << endl; } int _z;};typedef void (*V_F) ();void PRintVtable(int vptr){ int * ptr = (int *)vptr; printf("虛表:0x%p/n",ptr); for (int i = 0; ptr[i] != 0; i++) //通常虛表以0為結束標志; { V_F f = (V_F)ptr[i]; f(); }}void test(){ Z z; PrintVtable(*(int*)(&z));}運行截圖:
多繼承的虛函數表:
class T{public: virtual void fun1() { cout << "T::fun1()" << endl; } virtual void fun2() { cout << "T::fun2()" << endl; } int _t;};class Z {public: virtual void fun1() { cout << "Z::fun1()" << endl; } virtual void fun2() { cout << "Z::fun2()" << endl; } int _z;};class P : public Z,public T{public: virtual void fun1() { cout << "P::fun1()" << endl; } virtual void fun3() { cout << "P::fun3()" << endl; }};typedef void (*V_F) ();void PrintVtable(int vptr){ int * ptr = (int *)vptr; printf("虛表:0x%p/n",ptr); for (int i = 0; ptr[i] != 0; i++) //通常虛表以0為結束標志; { V_F f = (V_F)ptr[i]; f(); }}void test(){ P p; PrintVtable(*(int *)(&p));}運行截圖:
可以看出在虛函數表中沒有出現虛函數T::fun2();這是因為派生類中的虛函數會放在第一個繼承的虛表中;
新聞熱點
疑難解答