栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++虚函数表深度剖析

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++虚函数表深度剖析

使用命令
g++ g++ -fdump-lang-class main.cpp
VScl /d1 reportAllClassLayout main.cpp

以下以g++环境进行分析

单继承
class Base
{
public:
    Base(int a = 1, int b = 2){};
    virtual void fun1();
    virtual void func2(){};

private:
    int a = 1;
    int b = 1;
};

class Derive : public Base
{
public:
    Derive(int a = 1, int b = 2) : Base(a, b){};

private:
    int a = 1;
    int b = 1;
};

 通过实践 g++ -fdump-lang-class main.cpp,如图注释,vptr确切翻译应该为虚指针, 指向第一个虚函数地址而不是虚函数表地址。vptr指向的是虚函数表的首地址地址+16的位置,这不正好是func的地址么。

Vtable for Base  //Base的虚函数表
Base::_ZTV4Base: 4 entries
0     (int (*)(...))0              //top_offset多继承情况下使用
8     (int (*)(...))(& _ZTI4Base)  //RTTI类型,typeid(), dynamic_cast使用的就是这个
16    (int (*)(...))Base::fun1
24    (int (*)(...))Base::func2

Class Base
   size=16 align=8
   base size=16 base align=8
Base (0x0x7f04d7259420) 0
    vptr=((& Base::_ZTV4Base) + 16)

Vtable for Derive   //Derive的虚函数表
Derive::_ZTV6Derive: 4 entries
0     (int (*)(...))0                 //top_offset多继承情况下使用
8     (int (*)(...))(& _ZTI6Derive)   //RTTI类型,typeid(), dynamic_cast使用的就是这个
16    (int (*)(...))Base::fun1
24    (int (*)(...))Base::func2

Class Derive
   size=24 align=8             //对齐后的总大小,内存对齐大小
   base size=24 base align=8   //没有对齐的情况下的大小
Derive (0x0x7f04d71051a0) 0
    vptr=((& Derive::_ZTV6Derive) + 16)  //虚函数指针,指向Derive虚函数表的第一个虚函数
  Base (0x0x7f04d7259660) 0
      primary-for Derive (0x0x7f04d71051a0)
多继承
class Base
{
public:
    Base(int a = 1, int b = 2){};
    virtual void fun1();
    virtual void func2(){};

private:
    int a = 1;
    int b = 1;
};


class Base1
{
public:
    Base1(int a = 1, int b = 2){};
    virtual void fun3();
    virtual void func4(){};

private:
    int a = 1;
    int b = 1;
};

class Base2
{
public:
    Base2(int a = 1, int b = 2){};
    virtual void fun3();
    virtual void func4(){};

private:
};

class Derive : public Base, Base1, Base2
{
public:
    Derive(int a = 1, int b = 2) : Base(a, b), Base1(a, b), Base2(a, b){};
private:
    int a = 1;
    int b = 1;
};

 通过 g++ -fdump-lang-class main.cpp, 结果如图,多继承的情况下的内存布局,这里我使用的是64位服务器,所以vptr是8字节,内存对齐也是按8字节对齐。

内存布局和虚函数表的top-offset偏移量可以看出,内存是先存储第一直接基类的vptr(覆盖后)和成员变量,然后是以此是第二和第三基类的vptr和成员变量,这里的虚函数表就填入了top-offset,他就是Base1:vptr的偏移量等等。

Vtable for Base
Base::_ZTV4Base: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4Base)
16    (int (*)(...))Base::fun1
24    (int (*)(...))Base::func2

Class Base
   size=16 align=8
   base size=16 base align=8
Base (0x0x7fc61fd92420) 0
    vptr=((& Base::_ZTV4Base) + 16)

Vtable for Base1
Base1::_ZTV5Base1: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5Base1)
16    (int (*)(...))Base1::fun3
24    (int (*)(...))Base1::func4

Class Base1
   size=16 align=8
   base size=16 base align=8
Base1 (0x0x7fc61fd92660) 0
    vptr=((& Base1::_ZTV5Base1) + 16)

Vtable for Base2
Base2::_ZTV5Base2: 4 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5Base2)
16    (int (*)(...))Base2::fun3
24    (int (*)(...))Base2::func4

Class Base2
   size=8 align=8
   base size=8 base align=8
Base2 (0x0x7fc61fd928a0) 0 nearly-empty
    vptr=((& Base2::_ZTV5Base2) + 16)

Vtable for Derive
Derive::_ZTV6Derive: 12 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI6Derive)
16    (int (*)(...))Base::fun1
24    (int (*)(...))Base::func2
32    (int (*)(...))-16
40    (int (*)(...))(& _ZTI6Derive)
48    (int (*)(...))Base1::fun3
56    (int (*)(...))Base1::func4
64    (int (*)(...))-32
72    (int (*)(...))(& _ZTI6Derive)
80    (int (*)(...))Base2::fun3
88    (int (*)(...))Base2::func4

Class Derive
   size=48 align=8                        //48可以看出是有三个vptr
   base size=48 base align=8
Derive (0x0x7fc61fdaa348) 0
    vptr=((& Derive::_ZTV6Derive) + 16)   //第一个虚指针
  Base (0x0x7fc61fd92ae0) 0
      primary-for Derive (0x0x7fc61fdaa348)
  Base1 (0x0x7fc61fd92b40) 16             //这里的16对象内存偏移量
      vptr=((& Derive::_ZTV6Derive) + 48)  //第二个虚指针
  Base2 (0x0x7fc61fd92ba0) 32 nearly-empty  //这里的32对象内存偏移量
      vptr=((& Derive::_ZTV6Derive) + 80)  //第三个个虚指针

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1019561.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号