虛函數表是C++類中存放虛函數的一張表,理解虛函數表對於理解多態很重要。html
本次使用的編譯器是VS2013,爲了簡化操做,不用去操做函數指針,我使用到了VS的CL編譯選項來查看類的內存佈局。ios
CL使用方法:函數
(1)在開始菜單中的vs目錄下打開"Visual Studio Tools"目錄,找到"VS2013 開發人員命令提示",打開它;佈局
(2)將你要編譯的文件放到該命令行對應的文件夾中。spa
(3)輸入cl "文件名" /d1reportSingleClassLayout"類名"命令行
(具體的使用方法能夠參考如下博客:http://www.cnblogs.com/dsky/archive/2012/02/07/2340984.html)指針
例子:code
#include <iostream> using namespace std; class C { public: int a; int b; }; int main() { return 0; }
輸出結果:htm
(1)單個類的虛函數表blog
class C { public: virtual void foo() {} int m; };
結果分析:能夠看見虛表處於類的最開始處,這是爲了提升效率和正確查找虛函數。
(2)單繼承
class Base { public: virtual void v1() {} int b; }; class Derived : public Base { public: virtual void v2() {} int d; };
結果分析:在類Derived的最前面是類Base,與咱們所預期的同樣。虛表並非Base和Derived都有,而是隻有Base有,Derived中的虛函數放在了Base裏的虛表中。
(3)單繼承 + 覆蓋
class Base { public: virtual void v1() {} int b; }; class Derived : public Base { public: virtual void v1() {} virtual void v2() {} int d; };
結果分析:咱們在Derived中覆蓋了Base的v1,從結果能夠看出虛表中原來的Base::v1變爲了Derived::v1
(4)多繼承
class Base1 { public: virtual void v1() {} int b1; }; class Base2 { public: virtual void v2() {} int b2; }; class Derived : public Base1, public Base2 { public: virtual void v3() {} int d; };
結果分析:兩個基類各自有本身的虛表,而Derived的虛函數放在了第一張虛表中。
(5)虛繼承
class VBase { public: virtual void vb1(){} int vb; }; class Base1 : virtual public VBase { public: virtual void v1() {} int b1; }; class Base2 : virtual public VBase { public: virtual void v2() {} int b2; }; class Derived : public Base1, public Base2 { public: virtual void v3() {} int d; };
結果分析:虛繼承後,基類中多了一張虛類表(vbtable),該虛類表記錄的是到虛類的偏移量,好比4+24 = 28。而虛函數表的狀況一如咱們以前討論。再細看,咱們發現虛基類並不做爲繼承類的一部分,而是由虛類表來找到。