C++ 对象模型(内存存储布局)
GCC 不同继承方式下的内存存储模型
以下是在 GCC 下的单继承、多继承、虚继承的虚表、虚表列表内存存储布局情况。
在 GCC 下可以使用 -fdump-lang-class 选项显示类的内部布局情况。
单继承
单继承无重写
struct Base {
int var1;
virtual ~Base() {}
virtual void func1() {}
};
struct Derived: public Base {
int var2;
virtual void func2() {}
};类和实例的内存布局情况如下所示:
Vtable for Base // Base 虚表
Base::_ZTV4Base: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI4Base) // Base 的 typeinfo
16 (int (*)(...))Base::~Base // 析构函数本身
24 (int (*)(...))Base::~Base // 析构函数 thunk(包含了调用析构函数本身、delete 过程以及一些其他内容)
32 (int (*)(...))Base::func1 // Base 的 func1 函数
// Base 实例化的内存布局情况
Class Base
size=16 align=8
base size=12 base align=8
Base (0x0x1340cf00) 0 // 表示 Base 的偏移量为 0
vptr=((& Base::_ZTV4Base) + 16) // 指向虚表第三个元素(偏移量为 16 字节)
Vtable for Derived // Derived 虚表
Derived::_ZTV7Derived: 6 entries
0 (int (*)(...))0 // 用于计算 Base 指针调用函数时的 this 指针,与 Base 共用前一部分的虚表
8 (int (*)(...))(& _ZTI7Derived) // Derived 的 typeinfo
16 (int (*)(...))Derived::~Derived // 析构函数本身,会调用基类构造函数
24 (int (*)(...))Derived::~Derived // 析构函数 thunk(包含了调用析构函数本身、delete 过程以及一些其他内容)
32 (int (*)(...))Base::func1 // Base 的 func1 函数
40 (int (*)(...))Derived::func2 // Derived 的 func2 函数
// Derived 实例化的内存布局情况
Class Derived
size=16 align=8
base size=16 base align=8
Derived (0x0x13412dd0) 0 // 表示 Derived 的偏移量为 0
vptr=((& Derived::_ZTV7Derived) + 16) // 指向虚表第三个元素(偏移量为 16 字节)
Base (0x0x1344e240) 0 // 表示 Base 的偏移量为 0
primary-for Derived (0x0x13412dd0) // 与基类共用 vptrDerived 类实例和虚表可视化内存布局情况如下图所示:
单继承有重写
struct Base {
int var1;
virtual ~Base() {}
virtual void func1() {}
};
struct Derived: public Base {
int var2;
void func1() override {}
};类和实例的内存布局情况如下所示:
Vtable for Base
Base::_ZTV4Base: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI4Base)
16 (int (*)(...))Base::~Base
24 (int (*)(...))Base::~Base
32 (int (*)(...))Base::func1 // Base 的 func1 函数
Class Base
size=16 align=8
base size=12 base align=8
Base (0x0x133fcf00) 0
vptr=((& Base::_ZTV4Base) + 16)
Vtable for Derived
Derived::_ZTV7Derived: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Derived)
16 (int (*)(...))Derived::~Derived
24 (int (*)(...))Derived::~Derived
32 (int (*)(...))Derived::func1 // Derived 重写了 Base 的 func1 函数
Class Derived
size=16 align=8
base size=16 base align=8
Derived (0x0x13402dd0) 0
vptr=((& Derived::_ZTV7Derived) + 16)
Base (0x0x1343e240) 0
primary-for Derived (0x0x13402dd0)Derived 类实例和虚表可视化内存布局情况如下图所示:
多继承
多继承无重写
struct Base1 {
int var1;
virtual ~Base1() {}
virtual void func1() {}
};
struct Base2 {
int var2;
virtual ~Base2() {}
virtual void func2() {}
};
struct Derived: public Base1, public Base2 {
int var3;
virtual void func3() {}
};类和实例的内存布局情况如下所示:
Vtable for Base1
Base1::_ZTV5Base1: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base1)
16 (int (*)(...))Base1::~Base1
24 (int (*)(...))Base1::~Base1
32 (int (*)(...))Base1::func1 // Base1 的 func1 函数
Class Base1
size=16 align=8
base size=12 base align=8
Base1 (0x0x13314f00) 0
vptr=((& Base1::_ZTV5Base1) + 16)
Vtable for Base2
Base2::_ZTV5Base2: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base2)
16 (int (*)(...))Base2::~Base2
24 (int (*)(...))Base2::~Base2
32 (int (*)(...))Base2::func2 // Base2 的 func2 函数
Class Base2
size=16 align=8
base size=12 base align=8
Base2 (0x0x13356240) 0
vptr=((& Base2::_ZTV5Base2) + 16)
Vtable for Derived
Derived::_ZTV7Derived: 11 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Derived) // Derived 的 typeinfo
16 (int (*)(...))Derived::~Derived
24 (int (*)(...))Derived::~Derived
32 (int (*)(...))Base1::func1 // Base1 的 func1 函数,未重写
40 (int (*)(...))Derived::func3 // Derived 的 func3 函数
48 (int (*)(...))-16 // Base2:用于计算 this 指向,因为 Base2 指针与 Derived 指针实际有 16 字节的偏移,所以在调用函数时需要将 Base2 指针减去 16 字节作为 this 指针,修改后实际指向 Derived 对象
56 (int (*)(...))(& _ZTI7Derived) // Base2:实际指向 Derived 的 typeinfo
64 (int (*)(...))Derived::_ZThn16_N7DerivedD1Ev // Base2 指针的析构函数,实际会跳转至 Derived 的析构函数
72 (int (*)(...))Derived::_ZThn16_N7DerivedD0Ev // Base2 指针的析构 thunk,实际会跳转至 Derived 的析构 thunk
80 (int (*)(...))Base2::func2 // Base2 的 func2 函数
Class Derived
size=32 align=8
base size=32 base align=8
Derived (0x0x12e6c7e0) 0
vptr=((& Derived::_ZTV7Derived) + 16) // Derived 的虚函数表指针指向 Vtable for Derived 的第 16 字节
Base1 (0x0x13356540) 0 // Base1 的偏移为 0 字节
primary-for Derived (0x0x12e6c7e0) // Base1 的虚函数表指针为与 Derived 一致
Base2 (0x0x133565a0) 16 // Base2 的偏移为 16 字节
vptr=((& Derived::_ZTV7Derived) + 64) // Base2 的虚函数表指针指向 Vtable for Derived 的第 64 字节Derived 类实例和虚表可视化内存布局情况如下图所示:
多继承有重写
struct Base1 {
int var1;
virtual ~Base1() {}
virtual void func1() {}
};
struct Base2 {
int var2;
virtual ~Base2() {}
virtual void func2() {}
};
struct Derived: public Base1, public Base2 {
int var3;
void func1() override {}
void func2() override {}
virtual void func3() {}
};类和实例的内存布局情况如下所示:
Vtable for Base1
Base1::_ZTV5Base1: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base1)
16 (int (*)(...))Base1::~Base1
24 (int (*)(...))Base1::~Base1
32 (int (*)(...))Base1::func1 // Base1 的 func1 函数
Class Base1
size=16 align=8
base size=12 base align=8
Base1 (0x0x13333f00) 0
vptr=((& Base1::_ZTV5Base1) + 16)
Vtable for Base2
Base2::_ZTV5Base2: 5 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base2)
16 (int (*)(...))Base2::~Base2
24 (int (*)(...))Base2::~Base2
32 (int (*)(...))Base2::func2 // Base2 的 func2 函数
Class Base2
size=16 align=8
base size=12 base align=8
Base2 (0x0x13375240) 0
vptr=((& Base2::_ZTV5Base2) + 16)
Vtable for Derived
Derived::_ZTV7Derived: 12 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Derived) // Derived 的 typeinfo
16 (int (*)(...))Derived::~Derived
24 (int (*)(...))Derived::~Derived
32 (int (*)(...))Derived::func1 // Derived 的 func1 函数,已重写
40 (int (*)(...))Derived::func2 // Derived 的 func2 函数,已重写
48 (int (*)(...))Derived::func3 // Derived 的 func3 函数
56 (int (*)(...))-16 // 用于计算 Base2 调用函数时的 this 指针
64 (int (*)(...))(& _ZTI7Derived) // Derived 的 typeinfo
72 (int (*)(...))Derived::_ZThn16_N7DerivedD1Ev // Base2 指针的析构函数,实际会跳转至 Derived 的析构函数
80 (int (*)(...))Derived::_ZThn16_N7DerivedD0Ev // Base2 指针的析构 thunk,实际会跳转至 Derived 的析构 thunk
88 (int (*)(...))Derived::_ZThn16_N7Derived5func2Ev // Base2 指针的 func2 函数,实际会跳转至 Derived 的 func2 函数
Class Derived
size=32 align=8 // 大小为 32 字节,按 8 字节对齐
base size=32 base align=8
Derived (0x0x12e8b7e0) 0
vptr=((& Derived::_ZTV7Derived) + 16) // 与 Base1 共用的虚函数表指针
Base1 (0x0x13375540) 0
primary-for Derived (0x0x12e8b7e0) // 与 Derived 共用虚函数表指针
Base2 (0x0x133755a0) 16
vptr=((& Derived::_ZTV7Derived) + 72) // Base2 的虚函数表指针Derived 类实例和虚表可视化内存布局情况如下图所示:
虚继承
简单虚继承(不含虚函数)
struct Base {
int var1;
void func1() {}
};
struct Derived: public virtual Base {
int var2;
void func2() {}
};类和实例的内存布局情况如下所示:
Class Base
size=4 align=4
base size=4 base align=4
Base (0x0x133ccf00) 0
Vtable for Derived
Derived::_ZTV7Derived: 3 entries
0 12 // vbase offset,虚基类 Base 在 Derived 实例中的偏移量
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI7Derived) // Derived 的 typeinfo
VTT for Derived // Table of virtual table,虚表列表,用于存储指向不同虚函数表的指针
Derived::_ZTT7Derived: 1 entries
0 ((& Derived::_ZTV7Derived) + 24) // 表示 Derived 的虚函数表指针,此处实际指向了虚表结尾
Class Derived
size=16 align=8 // 大小为 16 字节,按 8 字节对齐
base size=12 base align=8
Derived (0x0x133d2c30) 0 // 表示 Derived 的偏移量
vptridx=0 vptr=((& Derived::_ZTV7Derived) + 24) // vptridx 表示在 vtt 表中的虚函数表指针偏移; vptr 表示 Derived 的的虚函数表指针,此处实际指向了虚表结尾
Base (0x0x1340c000) 12 virtual // 表示 Base 在 Derived 实例中的起始偏移,virtual 表示为虚基类
vbaseoffset=-24 // 从 Base 的位置到 Derived 的 vptr 的偏移量(用于反向定位,验证虚基类与派生类的关系)Derived 类实例和虚表可视化内存布局情况如下图所示:
简单虚继承(含虚函数)
struct Base {
int var1;
virtual ~Base() {}
virtual void func1() {}
virtual void func2() {}
};
struct Derived: public virtual Base {
int var2;
void func2() override {}
virtual void func3() {}
};类和实例的内存布局情况如下所示:
Vtable for Base
Base::_ZTV4Base: 6 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI4Base)
16 (int (*)(...))Base::~Base
24 (int (*)(...))Base::~Base
32 (int (*)(...))Base::func1
40 (int (*)(...))Base::func2
Class Base
size=16 align=8
base size=12 base align=8
Base (0x0x133cdf00) 0
vptr=((& Base::_ZTV4Base) + 16)
Vtable for Derived
Derived::_ZTV7Derived: 16 entries
0 16 // vbase offset,虚基类 Base 在 Derived 实例中的偏移量
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI7Derived) // typeinfo of Derived
24 (int (*)(...))Derived::func2 // Derived 的 func2 函数,已重写
32 (int (*)(...))Derived::func3 // Derived 的 func3 函数
40 (int (*)(...))Derived::~Derived // Derived 析构函数
48 (int (*)(...))Derived::~Derived // Derived 析构 thunk
56 18446744073709551600 // 实际是-16(无符号表示),用于指针调整
64 0
72 18446744073709551600 // 实际是-16(无符号表示),用于指针调整
80 (int (*)(...))-16 // 用于计算 Base 指针调用函数时的 this 指针
88 (int (*)(...))(& _ZTI7Derived) // typeinfo of Derived
96 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD1Ev // Base2 指针的析构函数,实际会跳转至 Derived 的析构函数
104 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD0Ev // Base2 指针的析构 thunk,实际会跳转至 Derived 的析构 thunk
112 (int (*)(...))Base::func1 // Base 的 func1 函数
120 (int (*)(...))Derived::_ZTv0_n40_N7Derived5func2Ev // Base 指针的 func2 函数,实际会跳转至 Derived 的 func2 函数
VTT for Derived
Derived::_ZTT7Derived: 2 entries
0 ((& Derived::_ZTV7Derived) + 24) // 表示 Derived 的虚函数表指针
8 ((& Derived::_ZTV7Derived) + 96) // 表示 Base 的虚函数表指针
Class Derived
size=32 align=8
base size=12 base align=8
Derived (0x0x133d3e38) 0
vptridx=0 vptr=((& Derived::_ZTV7Derived) + 24) // vptridx 表示在 vtt 表中的虚函数表指针偏移; vptr 表示 Derived 的的虚函数表指针
Base (0x0x1340f2a0) 16 virtual
vptridx=8 vbaseoffset=-24 vptr=((& Derived::_ZTV7Derived) + 96) // 表示从 Base 的 vptr 位置到 Derived 对象起始位置的偏移量;vptr 表示 Base 的的虚函数表指针Derived 类实例和虚表可视化内存布局情况如下图所示:
菱形继承
struct Base1 {
int var1;
virtual ~Base1() {}
virtual void func1() {}
virtual void func2() {}
};
struct Base2: public virtual Base1 {
int var2;
void func1() override {}
virtual void func3() {}
};
struct Base3: public virtual Base1 {
int var3;
void func1() override {}
virtual void func4() {}
};
struct Derived: public Base2, public Base3 {
int var4;
void func1() override {}
void func3() override {}
virtual void func5() {}
};类和实例的内存布局情况如下所示:
Vtable for Base1
Base1::_ZTV5Base1: 6 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base1)
16 (int (*)(...))Base1::~Base1
24 (int (*)(...))Base1::~Base1
32 (int (*)(...))Base1::func1
40 (int (*)(...))Base1::func2
Class Base1
size=16 align=8
base size=12 base align=8
Base1 (0x0x133faf00) 0
vptr=((& Base1::_ZTV5Base1) + 16)
Vtable for Base2
Base2::_ZTV5Base2: 16 entries
0 16
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI5Base2)
24 (int (*)(...))Base2::func1
32 (int (*)(...))Base2::func3
40 (int (*)(...))Base2::~Base2
48 (int (*)(...))Base2::~Base2
56 0
64 18446744073709551600
72 18446744073709551600
80 (int (*)(...))-16
88 (int (*)(...))(& _ZTI5Base2)
96 (int (*)(...))Base2::_ZTv0_n24_N5Base2D1Ev
104 (int (*)(...))Base2::_ZTv0_n24_N5Base2D0Ev
112 (int (*)(...))Base2::_ZTv0_n32_N5Base25func1Ev
120 (int (*)(...))Base1::func2
VTT for Base2
Base2::_ZTT5Base2: 2 entries
0 ((& Base2::_ZTV5Base2) + 24)
8 ((& Base2::_ZTV5Base2) + 96)
Class Base2
size=32 align=8
base size=12 base align=8
Base2 (0x0x13400e38) 0
vptridx=0 vptr=((& Base2::_ZTV5Base2) + 24)
Base1 (0x0x1343c2a0) 16 virtual
vptridx=8 vbaseoffset=-24 vptr=((& Base2::_ZTV5Base2) + 96)
Vtable for Base3
Base3::_ZTV5Base3: 16 entries
0 16
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI5Base3)
24 (int (*)(...))Base3::func1
32 (int (*)(...))Base3::func4
40 (int (*)(...))Base3::~Base3
48 (int (*)(...))Base3::~Base3
56 0
64 18446744073709551600
72 18446744073709551600
80 (int (*)(...))-16
88 (int (*)(...))(& _ZTI5Base3)
96 (int (*)(...))Base3::_ZTv0_n24_N5Base3D1Ev
104 (int (*)(...))Base3::_ZTv0_n24_N5Base3D0Ev
112 (int (*)(...))Base3::_ZTv0_n32_N5Base35func1Ev
120 (int (*)(...))Base1::func2
VTT for Base3
Base3::_ZTT5Base3: 2 entries
0 ((& Base3::_ZTV5Base3) + 24)
8 ((& Base3::_ZTV5Base3) + 96)
Class Base3
size=32 align=8
base size=12 base align=8
Base3 (0x0x13400ea0) 0
vptridx=0 vptr=((& Base3::_ZTV5Base3) + 24)
Base1 (0x0x1343c3c0) 16 virtual
vptridx=8 vbaseoffset=-24 vptr=((& Base3::_ZTV5Base3) + 96)
Vtable for Derived
Derived::_ZTV7Derived: 24 entries
0 32
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI7Derived)
24 (int (*)(...))Derived::func1
32 (int (*)(...))Derived::func3
40 (int (*)(...))Derived::~Derived
48 (int (*)(...))Derived::~Derived
56 (int (*)(...))Derived::func5
64 16
72 (int (*)(...))-16
80 (int (*)(...))(& _ZTI7Derived)
88 (int (*)(...))Derived::_ZThn16_N7Derived5func1Ev
96 (int (*)(...))Base3::func4
104 (int (*)(...))Derived::_ZThn16_N7DerivedD1Ev
112 (int (*)(...))Derived::_ZThn16_N7DerivedD0Ev
120 0
128 18446744073709551584
136 18446744073709551584
144 (int (*)(...))-32
152 (int (*)(...))(& _ZTI7Derived)
160 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD1Ev
168 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD0Ev
176 (int (*)(...))Derived::_ZTv0_n32_N7Derived5func1Ev
184 (int (*)(...))Base1::func2
Construction vtable for Base2 (0x0x13445138 instance) in Derived // 构造 Derived 时 Base2 阶段的临时 vtable
Derived::_ZTC7Derived0_5Base2: 16 entries
0 32
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI5Base2)
24 (int (*)(...))Base2::func1
32 (int (*)(...))Base2::func3
40 0
48 0
56 0
64 18446744073709551584
72 18446744073709551584
80 (int (*)(...))-32
88 (int (*)(...))(& _ZTI5Base2)
96 0
104 0
112 (int (*)(...))Base2::_ZTv0_n32_N5Base25func1Ev
120 (int (*)(...))Base1::func2
Construction vtable for Base3 (0x0x134451a0 instance) in Derived // 构造 Derived 时 Base3 阶段的临时 vtable
Derived::_ZTC7Derived16_5Base3: 16 entries
0 16
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI5Base3)
24 (int (*)(...))Base3::func1
32 (int (*)(...))Base3::func4
40 0
48 0
56 0
64 18446744073709551600
72 18446744073709551600
80 (int (*)(...))-16
88 (int (*)(...))(& _ZTI5Base3)
96 0
104 0
112 (int (*)(...))Base3::_ZTv0_n32_N5Base35func1Ev
120 (int (*)(...))Base1::func2
VTT for Derived
Derived::_ZTT7Derived: 7 entries
0 ((& Derived::_ZTV7Derived) + 24)
8 ((& Derived::_ZTC7Derived0_5Base2) + 24)
16 ((& Derived::_ZTC7Derived0_5Base2) + 96)
24 ((& Derived::_ZTC7Derived16_5Base3) + 24)
32 ((& Derived::_ZTC7Derived16_5Base3) + 96)
40 ((& Derived::_ZTV7Derived) + 160)
48 ((& Derived::_ZTV7Derived) + 88)
Class Derived
size=48 align=8
base size=32 base align=8
Derived (0x0x12f6c7e0) 0
vptridx=0 vptr=((& Derived::_ZTV7Derived) + 24)
Base2 (0x0x13445138) 0
primary-for Derived (0x0x12f6c7e0)
subvttidx=8
Base1 (0x0x1343c4e0) 32 virtual
vptridx=40 vbaseoffset=-24 vptr=((& Derived::_ZTV7Derived) + 160)
Base3 (0x0x134451a0) 16
subvttidx=24 vptridx=48 vptr=((& Derived::_ZTV7Derived) + 88)
Base1 (0x0x1343c4e0) alternative-path // 确认Base1为共享实例(无冗余)Derived 类实例和虚表可视化内存布局情况如下图所示:
双菱形多继承
struct Base1 {
int var1;
virtual ~Base1() {}
virtual void func1() {}
virtual void func2() {}
};
struct Base2 {
int var2;
virtual ~Base2() {}
virtual void func3() {}
virtual void func4() {}
};
struct Base3: public virtual Base1, public virtual Base2 {
int var3;
void func1() override {}
void func3() override {}
virtual void func5() {}
};
struct Base4: public virtual Base1, public virtual Base2 {
int var4;
void func1() override {}
void func3() override {}
virtual void func6() {}
};
struct Derived: public Base3, public Base4 {
int var5;
void func1() override {}
void func3() override {}
void func5() override {}
virtual void func7() {}
};类和实例的内存布局情况如下所示:
Vtable for Base1
Base1::_ZTV5Base1: 6 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base1)
16 (int (*)(...))Base1::~Base1
24 (int (*)(...))Base1::~Base1
32 (int (*)(...))Base1::func1
40 (int (*)(...))Base1::func2
Class Base1
size=16 align=8
base size=12 base align=8
Base1 (0x0x13433f00) 0
vptr=((& Base1::_ZTV5Base1) + 16)
Vtable for Base2
Base2::_ZTV5Base2: 6 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI5Base2)
16 (int (*)(...))Base2::~Base2
24 (int (*)(...))Base2::~Base2
32 (int (*)(...))Base2::func3
40 (int (*)(...))Base2::func4
Class Base2
size=16 align=8
base size=12 base align=8
Base2 (0x0x134752a0) 0
vptr=((& Base2::_ZTV5Base2) + 16)
Vtable for Base3
Base3::_ZTV5Base3: 27 entries
0 32
8 16
16 (int (*)(...))0
24 (int (*)(...))(& _ZTI5Base3)
32 (int (*)(...))Base3::func1
40 (int (*)(...))Base3::func3
48 (int (*)(...))Base3::func5
56 (int (*)(...))Base3::~Base3
64 (int (*)(...))Base3::~Base3
72 0
80 18446744073709551600
88 18446744073709551600
96 (int (*)(...))-16
104 (int (*)(...))(& _ZTI5Base3)
112 (int (*)(...))Base3::_ZTv0_n24_N5Base3D1Ev
120 (int (*)(...))Base3::_ZTv0_n24_N5Base3D0Ev
128 (int (*)(...))Base3::_ZTv0_n32_N5Base35func1Ev
136 (int (*)(...))Base1::func2
144 0
152 18446744073709551584
160 18446744073709551584
168 (int (*)(...))-32
176 (int (*)(...))(& _ZTI5Base3)
184 (int (*)(...))Base3::_ZTv0_n24_N5Base3D1Ev
192 (int (*)(...))Base3::_ZTv0_n24_N5Base3D0Ev
200 (int (*)(...))Base3::_ZTv0_n32_N5Base35func3Ev
208 (int (*)(...))Base2::func4
VTT for Base3
Base3::_ZTT5Base3: 3 entries
0 ((& Base3::_ZTV5Base3) + 32)
8 ((& Base3::_ZTV5Base3) + 112)
16 ((& Base3::_ZTV5Base3) + 184)
Class Base3
size=48 align=8
base size=12 base align=8
Base3 (0x0x12f8b7e0) 0
vptridx=0 vptr=((& Base3::_ZTV5Base3) + 32)
Base1 (0x0x13475600) 16 virtual
vptridx=8 vbaseoffset=-24 vptr=((& Base3::_ZTV5Base3) + 112)
Base2 (0x0x13475660) 32 virtual
vptridx=16 vbaseoffset=-32 vptr=((& Base3::_ZTV5Base3) + 184)
Vtable for Base4
Base4::_ZTV5Base4: 27 entries
0 32
8 16
16 (int (*)(...))0
24 (int (*)(...))(& _ZTI5Base4)
32 (int (*)(...))Base4::func1
40 (int (*)(...))Base4::func3
48 (int (*)(...))Base4::func6
56 (int (*)(...))Base4::~Base4
64 (int (*)(...))Base4::~Base4
72 0
80 18446744073709551600
88 18446744073709551600
96 (int (*)(...))-16
104 (int (*)(...))(& _ZTI5Base4)
112 (int (*)(...))Base4::_ZTv0_n24_N5Base4D1Ev
120 (int (*)(...))Base4::_ZTv0_n24_N5Base4D0Ev
128 (int (*)(...))Base4::_ZTv0_n32_N5Base45func1Ev
136 (int (*)(...))Base1::func2
144 0
152 18446744073709551584
160 18446744073709551584
168 (int (*)(...))-32
176 (int (*)(...))(& _ZTI5Base4)
184 (int (*)(...))Base4::_ZTv0_n24_N5Base4D1Ev
192 (int (*)(...))Base4::_ZTv0_n24_N5Base4D0Ev
200 (int (*)(...))Base4::_ZTv0_n32_N5Base45func3Ev
208 (int (*)(...))Base2::func4
VTT for Base4
Base4::_ZTT5Base4: 3 entries
0 ((& Base4::_ZTV5Base4) + 32)
8 ((& Base4::_ZTV5Base4) + 112)
16 ((& Base4::_ZTV5Base4) + 184)
Class Base4
size=48 align=8
base size=12 base align=8
Base4 (0x0x12f8b850) 0
vptridx=0 vptr=((& Base4::_ZTV5Base4) + 32)
Base1 (0x0x134757e0) 16 virtual
vptridx=8 vbaseoffset=-24 vptr=((& Base4::_ZTV5Base4) + 112)
Base2 (0x0x13475840) 32 virtual
vptridx=16 vbaseoffset=-32 vptr=((& Base4::_ZTV5Base4) + 184)
Vtable for Derived
Derived::_ZTV7Derived: 37 entries
0 48
8 32
16 (int (*)(...))0
24 (int (*)(...))(& _ZTI7Derived)
32 (int (*)(...))Derived::func1
40 (int (*)(...))Derived::func3
48 (int (*)(...))Derived::func5
56 (int (*)(...))Derived::~Derived
64 (int (*)(...))Derived::~Derived
72 (int (*)(...))Derived::func7
80 32
88 16
96 (int (*)(...))-16
104 (int (*)(...))(& _ZTI7Derived)
112 (int (*)(...))Derived::_ZThn16_N7Derived5func1Ev
120 (int (*)(...))Derived::_ZThn16_N7Derived5func3Ev
128 (int (*)(...))Base4::func6
136 (int (*)(...))Derived::_ZThn16_N7DerivedD1Ev
144 (int (*)(...))Derived::_ZThn16_N7DerivedD0Ev
152 0
160 18446744073709551584
168 18446744073709551584
176 (int (*)(...))-32
184 (int (*)(...))(& _ZTI7Derived)
192 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD1Ev
200 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD0Ev
208 (int (*)(...))Derived::_ZTv0_n32_N7Derived5func1Ev
216 (int (*)(...))Base1::func2
224 0
232 18446744073709551568
240 18446744073709551568
248 (int (*)(...))-48
256 (int (*)(...))(& _ZTI7Derived)
264 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD1Ev
272 (int (*)(...))Derived::_ZTv0_n24_N7DerivedD0Ev
280 (int (*)(...))Derived::_ZTv0_n32_N7Derived5func3Ev
288 (int (*)(...))Base2::func4
Construction vtable for Base3 (0x0x12f8b930 instance) in Derived
Derived::_ZTC7Derived0_5Base3: 27 entries
0 48
8 32
16 (int (*)(...))0
24 (int (*)(...))(& _ZTI5Base3)
32 (int (*)(...))Base3::func1
40 (int (*)(...))Base3::func3
48 (int (*)(...))Base3::func5
56 0
64 0
72 0
80 18446744073709551584
88 18446744073709551584
96 (int (*)(...))-32
104 (int (*)(...))(& _ZTI5Base3)
112 0
120 0
128 (int (*)(...))Base3::_ZTv0_n32_N5Base35func1Ev
136 (int (*)(...))Base1::func2
144 0
152 18446744073709551568
160 18446744073709551568
168 (int (*)(...))-48
176 (int (*)(...))(& _ZTI5Base3)
184 0
192 0
200 (int (*)(...))Base3::_ZTv0_n32_N5Base35func3Ev
208 (int (*)(...))Base2::func4
Construction vtable for Base4 (0x0x12f8b9a0 instance) in Derived
Derived::_ZTC7Derived16_5Base4: 27 entries
0 32
8 16
16 (int (*)(...))0
24 (int (*)(...))(& _ZTI5Base4)
32 (int (*)(...))Base4::func1
40 (int (*)(...))Base4::func3
48 (int (*)(...))Base4::func6
56 0
64 0
72 0
80 18446744073709551600
88 18446744073709551600
96 (int (*)(...))-16
104 (int (*)(...))(& _ZTI5Base4)
112 0
120 0
128 (int (*)(...))Base4::_ZTv0_n32_N5Base45func1Ev
136 (int (*)(...))Base1::func2
144 0
152 18446744073709551584
160 18446744073709551584
168 (int (*)(...))-32
176 (int (*)(...))(& _ZTI5Base4)
184 0
192 0
200 (int (*)(...))Base4::_ZTv0_n32_N5Base45func3Ev
208 (int (*)(...))Base2::func4
VTT for Derived
Derived::_ZTT7Derived: 10 entries
0 ((& Derived::_ZTV7Derived) + 32)
8 ((& Derived::_ZTC7Derived0_5Base3) + 32)
16 ((& Derived::_ZTC7Derived0_5Base3) + 112)
24 ((& Derived::_ZTC7Derived0_5Base3) + 184)
32 ((& Derived::_ZTC7Derived16_5Base4) + 32)
40 ((& Derived::_ZTC7Derived16_5Base4) + 112)
48 ((& Derived::_ZTC7Derived16_5Base4) + 184)
56 ((& Derived::_ZTV7Derived) + 192)
64 ((& Derived::_ZTV7Derived) + 264)
72 ((& Derived::_ZTV7Derived) + 112)
Class Derived
size=64 align=8
base size=32 base align=8
Derived (0x0x12f8b8c0) 0
vptridx=0 vptr=((& Derived::_ZTV7Derived) + 32)
Base3 (0x0x12f8b930) 0
primary-for Derived (0x0x12f8b8c0)
subvttidx=8
Base1 (0x0x134759c0) 32 virtual
vptridx=56 vbaseoffset=-24 vptr=((& Derived::_ZTV7Derived) + 192)
Base2 (0x0x13475a20) 48 virtual
vptridx=64 vbaseoffset=-32 vptr=((& Derived::_ZTV7Derived) + 264)
Base4 (0x0x12f8b9a0) 16
subvttidx=32 vptridx=72 vptr=((& Derived::_ZTV7Derived) + 112)
Base1 (0x0x134759c0) alternative-path
Base2 (0x0x13475a20) alternative-pathDerived 类实例和虚表可视化内存布局情况如下图所示:
引用
最近更新于