多重继承和虚继承的内存布局,超级…

本文深入探讨了C++中虚继承和多重继承的对象内存布局,包括GCC编译器的处理方式。文章阐述了动态和静态类型转换的区别、虚函数表的结构,并通过实例解释了内存布局如何影响指针转换。通过理解这些概念,开发者可以更好地预测和处理代码中的潜在问题,提高代码效率。
摘要由CSDN通过智能技术生成

这篇文章主要讲解虚继承的C++对象内存分布问题,从中也引出了dynamic_cast和static_cast本质区别、虚函数表的格式等一些大部分C++程序员都似是而非的概念。原文见这里(By Edsko de Vries, January 2006)

 

 

      敬告本文是介绍C++的技术文章,假定读者对于C++有比较深入的认识,同时也需要一些汇编知识。

   本文我们将阐释GCC编译器针对多重继承和虚拟继承下的对象内存布局。尽管在理想的使用环境中,一个C++程序员并不需要了解这些编译器内部实现细节,实际上,编译器针对多重继承(特别是虚拟继承)的各种实现细节对于我们编写C++代码都或多或少产生一些影响(比如downcasting pointerpointers to pointers 以及虚基类构造函数的调用顺序)。如果你能明白多重继承是如何实现的,那么你自己就能够预见到这些影响,进而能够在你的代码中很好地应对它们。再者,如果你十分在意的代码的运行效率,正确地理解虚继承也是很有帮助的。最后嘛,这个hack的过程是很有趣的哦:)

   

多重继承

   首先我们先来考虑一个很简单(non-virtual)的多重继承。看看下面这个C++类层次结构。

 class Top
 {
 public:
    int a;
 };
 
 class Left : public Top
 {
 public:
10    int b;
11 };
12 
13 class Right : public Top
14 {
15 public:
16    int c;
17 };
18 
19 class Bottom : public Left, public Right
20 {
21 public:
22    int d;
23 };
24 

   UML表述如下:

    注意到Top类实际上被继承了两次,(这种机制在Eiffel中被称作repeated inheritance),这就意味着在一个bottom对象中实际上有两个a属性(attributes,可以通过bottom.Left::a和 bottom.Right::a访问) 

    那么LeftRightBottom在内存中如何分布的呢?我们先来看看简单的LeftRight内存分布:

       [Right 类的布局和Left是一样的,因此我这里就没再画图了。刺猬]

       注意到上面类各自的第一个属性都是继承自Top类,这就意味着下面两个赋值语句:

Left* left = new Left();
Top* top = left;

       lefttop实际上是指向两个相同的地址,我们可以把Left对象当作一个Top对象(同样也可以把Right对象当Top对象来使用)。但是Botom对象呢?GCC是这样处理的:

     但是现在如果我们upcast 一个Bottom指针将会有什么结果 

Bottom* bottom = new Bottom();
Left* left = bottom;
 

       这段代码运行正确。这是因为GCC选择的这种内存布局使得我们可以把Bottom对象当作Left对象,它们两者(Left部分)正好相同。但是,如果我们把Bottom对象指针upcastRight对象呢?

Right* right = bottom;

      如果我们要使这段代码正常工作的话,我们需要调整指针指向Bottom中相应的部分。

     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值