虚函数表是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。而虚函数表的状况一如咱们以前讨论。再细看,咱们发现虚基类并不做为继承类的一部分,而是由虚类表来找到。