深入理解C++虚函数表

  虚函数表是C++类中存放虚函数的一张表,理解虚函数表对于理解多态很重要。

  本次使用的编译器是VS2013,为了简化操作,不用去操作函数指针,我使用到了VS的CL编译选项来查看类的内存布局。

  CL使用方法:

  (1)在开始菜单中的vs目录下打开"Visual Studio Tools"目录,找到"VS2013 开发人员命令提示",打开它;

  (2)将你要编译的文件放到该命令行对应的文件夹中。

  (3)输入cl "文件名" /d1reportSingleClassLayout"类名"

  (具体的使用方法可以参考以下博客:http://www.cnblogs.com/dsky/archive/2012/02/07/2340984.html)

  例子:

#include <iostream>
using namespace std;

class C {
public:    
    int a;
    int b;
};

int main() {
    return 0;
}

  输出结果:

  (1)单个类的虚函数表

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

原文地址:https://www.cnblogs.com/programmer-kaima/p/4909275.html