4.9两层结构时虚基类表内容分析

tech2024-07-25  51

虚基类表内容之1-8字节内容分析

#include <iostream> using namespace std; class Grand //爷爷类 { public: int m_grand; }; class A1 : virtual public Grand { public: int m_a1; }; class A2 : virtual public Grand { public: int m_a2; }; class C1 :public A1, public A2 { public: int m_c1; }; int main() { //一:虚基类表内容之5-8字节内容分析 //虚基类表 一般是8字节,四个字节为一个单位。每多一个虚基类,虚基类表会多加4个字节 //编译器因为有虚基类,会给A1,A2类增加默认的构造函数,并且这个默认构造函数里,会被编译器增加进去代码, //给vbptr虚基类表指针赋值。 cout << sizeof(Grand) << endl; cout << sizeof(A1) << endl; cout << sizeof(A2) << endl; cout << sizeof(C1) << endl; /* 4 24 24 48 */ A1 a1obj; a1obj.m_grand = 2; a1obj.m_a1 = 5; //“虚基类表指针”成员变量的首地址 + 这个偏移量 就等于 虚基类对象首地址。跳过这个偏移值,我们就能够访问到虚基类对象; //三:虚基类表内容之1-4字节内容分析 //虚基类表指针成员变量的首地址 ,和本对象A1首地址之间的偏移量 也就是:虚基类表指针 的首地址 - A1对象的首地址 //结论:只有对虚基类成员进行处理比如赋值的时候,才会用到虚基类表,取其中的偏移,参与地址的计算; return 1; }

A1对象的结构: 1-8字节虚基类表指针,m_a1,补齐,m_grand,补齐 可以看到,虚基类表地址0x00007FF72A019BD8 5-8字节表示偏移16字节,“虚基类表指针”成员变量的首地址 + 这个偏移量 就等于 虚基类对象首地址(这里是m_grand首地址)。跳过这个偏移值,我们就能够访问到虚基类对象。 1-4字节:虚基类表指针成员变量的首地址 ,和本对象A1首地址之间的偏移量 也就是:虚基类表指针 的首地址 - A1对象的首地址,这里正好为0。

复杂继承

A1虚继承Grand和实继承Grand2

#include <iostream> using namespace std; class Grand //爷爷类 { public: int m_grand; }; class Grand2 //爷爷类 { public: int m_grand2; //int m_grand2_1; }; class A1 : virtual public Grand, public Grand2//实继承Grand2 { public: int m_a1; }; class A2 : virtual public Grand { public: int m_a2; }; class C1 :public A1, public A2 { public: int m_c1; }; int main() { cout << sizeof(Grand) << endl; cout << sizeof(A1) << endl; cout << sizeof(A2) << endl; cout << sizeof(C1) << endl; /* 4 32 24 56 */ A1 a1obj; a1obj.m_grand = 2; a1obj.m_grand2 = 6; a1obj.m_a1 = 5; return 1; }

A1对象32字节 实继承来的m_grand2在最前面,补齐,虚基类指针,m_a1,补齐,m_grand(虚基类继承来的最后),补齐 可以看到虚基类表地址0x00007FF7144C9BD8

5-8字节表示偏移16字节,“虚基类表指针”成员变量的首地址 + 这个偏移量 就等于 虚基类对象首地址(这里是m_grand首地址)。跳过这个偏移值,我们就能够访问到虚基类对象。 1-4字节:虚基类表指针成员变量的首地址 ,和本对象A1首地址之间的偏移量 也就是:虚基类表指针 的首地址 - A1对象的首地址,这里是-8(fffffff8)。

A1虚继承Grand和Grand2

#include <iostream> using namespace std; class Grand //爷爷类 { public: int m_grand; }; class Grand2 //爷爷类 { public: int m_grand2; }; class A1 : virtual public Grand, virtual public Grand2 { public: int m_a1; }; class A2 : virtual public Grand { public: int m_a2; }; class C1 :public A1, public A2 { public: int m_c1; }; int main() { cout << sizeof(Grand) << endl; cout << sizeof(A1) << endl; cout << sizeof(A2) << endl; cout << sizeof(C1) << endl; /* 4 24 24 48 */ A1 a1obj; a1obj.m_grand = 2; a1obj.m_grand2 = 6; a1obj.m_a1 = 5; return 1; }

虚基类指针,m_a1,补齐,m_grand,m_grand2(虚基类继承来的都在最后面,虚基类指针在最前面) 可以看到虚基类表地址0x00007FF697CD9D78 现在多了4字节 前4字节:虚基类表指针成员变量的首地址 ,和本对象A1首地址之间的偏移量 也就是:虚基类表指针 的首地址 - A1对象的首地址,这里是0 5-8字节表示偏移16字节,“虚基类表指针”成员变量的首地址 + 这个偏移量 就等于 虚基类对象首地址(这里是m_grand首地址)。跳过这个偏移值,我们就能够访问到虚基类Grand对象。 9-12:偏移20字节,跳过20字节能访问到虚基类Grand2对象(m_grand2首地址)

最新回复(0)