C++虚继承实现原理——解决菱形继承问题

男娘i 2022-04-17 01:42 356阅读 0赞

首先给出以下继承关系,以便描述虚继承原理:

  1. class AAA
  2. {
  3. public:
  4. int age;
  5. };
  6. class BBB:virtual public AAA//变为虚继承,A变为虚基类
  7. {
  8. };
  9. class CCC:virtual public AAA
  10. {
  11. };
  12. class DDD:public BBB, public CCC
  13. {
  14. };

命令格式如下:
cl –d1reportSingleClassLayout[classname] xxx.cpp

  • classname 为类名,-d1reportSingleClassLayout[classname] 之间没有空格。
  • xxx.cpp为源代码文件名

通过vs中的开发人员命令提示窗口得到类的内存布局:class DDD中左边的数字代表偏移量,vpter(virtual base table pointer)是虚基类表指针,指向的是虚基类表的表头;vbtable(virtual base table)是虚基类表,类中保存的父类指针指向了虚基类表中的表头(指针),而对这个表头+1进行寻址操作即可得到虚基类表中所记录的偏移量。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hlbGxvX015RHJlYW0_size_16_color_FFFFFF_t_70

一.以下代码为通过BBB的虚基类指针得到此指针位置相对于成员变量age的偏移量,并根据偏移量计算出对应成员变量age的值。

  1. DDD d;
  2. d.age = 10;
  3. cout << *((int *)*(int **)&d + 1) << endl;//8
  4. cout << ((AAA *)((char *)&d + *((int *)*(int **)&d + 1)))->age << endl;//10
  5. cout << *(int *)((char *)&d + *((int *)*(int **)&d + 1)) << endl;//10
  1. 目的:的到虚基类表中所记录的vbptr指针相对于父类成员(age)的偏移量。
  2. 先取得最低派生类的地址,强转为int**类型,即只取四个字节的地址,得到的便是vbptr指针的地址。
  3. 再对这个指针寻址*,得到的便是 在Sheep虚基类表中指向表头的一级指针,此时将这个指针强转为 int*类型再加+1,使其指向虚基类表中记录的偏移量,再对这个指针进行寻址,得到的就是偏移量的值了。
  4. 得到偏移量后,使用BBB的vbptr指针的起始位置加上这个偏移量,然后强转为AAA*类型,然后再次进行指向操作,便可以得到age的值了。
  5. 当然还可以对找到的成员变量age的地址直接解引用得到age的值。

需要注意的是:这里只能将地址转为AAA*类型做指向操作,BBB、CCC、DDD均不可以,因为内存结构都不相同。只有AAA是在首地址位置就就代表了成员变量age,而BBB、CCC则是保存的vbptr,DDD保存的是两个vbptr指针与一个age变量(当然这个变量也是它们的顶级父类AAA的)。

二.通过CCC的虚基类指针得到此指针位置相对于成员变量age的偏移量,并根据偏移量计算出对应成员变量age的值。

  1. cout << *((int *)*(int **)((int **)&d + 1) + 1) << endl;//4
  2. cout << ( (AAA *) ((char *)((int *)&d + 1) + *((int *)*(int **)((int **)&d + 1) + 1)) )->age << endl;//10
  3. cout << *(int *)( ((char *)((int *)&d + 1) + *((int *)*(int **)((int **)&d + 1) + 1)) )<< endl;
  1. 目的:通过Tuo的虚基类指针得到此指针对于age的偏移量。
  2. 还是&d,然后再转为int**类型,此时要先+1得到Tuo的vbptr指针,之后再转为int**类型进行寻址,得到Tuo虚基类表中指向表头的一级指针,之后再转为int类型,再次寻址,得到偏移量4。
  3. 强转为AAA*类型指向age。
  4. 将地址转为int*类型解引用。

发表评论

表情:
评论列表 (有 0 条评论,356人围观)

还没有评论,来说两句吧...

相关阅读

    相关 C++:53---菱形继承继承

    一、菱形继承 在介绍虚继承之前介绍一下菱形继承 概念:A作为基类,B和C都继承与A。最后一个类D又继承于B和C,这样形式的继承称为菱形继承 菱形继承的缺