需要實作多态必不可少的就是虛函數,類的成員函數前加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();這是因為派生類中的虛函數會放在第一個繼承的虛表中;