欢迎来到天天文库
浏览记录
ID:28859768
大小:161.50 KB
页数:15页
时间:2018-12-14
《多重继承地内存分布》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、实用标准文案指针的比较 再以上面Bottom类继承关系为例讨论,下面这段代码会打印Equal吗?1 Bottom*b= new Bottom(); 2 Right*r=b;3 4 if(r==b)5 printf("Equal!/n"); 先明确下这两个指针实际上是指向不同地址的,r指针实际上在b指针所指地址上偏移8字节,但是,这些C++内部细节不能告诉C++程序员,所以C++编译器在比较r和b时,会把r减去8字节,然后再来比较,所以打印出的值是"Equal".多重继承 首
2、先我们先来考虑一个很简单(non-virtual)的多重继承。看看下面这个C++类层次结构。 1 class Top 2 { 3 public: 4 int a; 5 }; 6 7 class Left: public Top 8 { 9 public:10 int b;11 };12 13 class Right: public Top14 {15 public:16 int c;17 };18 19 class Bottom: public Left, public Rig
3、ht20 {21 public:22 int d;23 };24 用UML表述如下:精彩文档实用标准文案 注意到Top类实际上被继承了两次,(这种机制在Eiffel中被称作repeated inheritance),这就意味着在一个bottom对象中实际上有两个a属性(attributes,可以通过bottom.Left::a和 bottom.Right::a访问) 。那么Left、Right、Bottom在内存中如何分布的呢?我们先来看看简单的Left和Right内存分布:
4、 [Right类的布局和Left是一样的,因此我这里就没再画图了。刺猬] 注意到上面类各自的第一个属性都是继承自Top类,这就意味着下面两个赋值语句:1 Left*left= new Left();2 Top*top=left; left和top实际上是指向两个相同的地址,我们可以把Left对象当作一个Top对象(同样也可以把Right对象当Top对象来使用)。但是Botom对象呢?GCC是这样处理的:精彩文档实用标准文案 但是现在如果我们upcast 一个Bo
5、ttom指针将会有什么结果? 1 Bottom*bottom= new Bottom();2 Left*left=bottom; 这段代码运行正确。这是因为GCC选择的这种内存布局使得我们可以把Bottom对象当作Left对象,它们两者(Left部分)正好相同。但是,如果我们把Bottom对象指针upcast到Right对象呢?1 Right*right=bottom; 如果我们要使这段代码正常工作的话,我们需要调整指针指向Bottom中相应的部分。 通过调整,我
6、们可以用right指针访问Bottom对象,这时Bottom对象表现得就如Right对象。但是bottom和right指针指向了不同的内存地址。最后,我们考虑下:1 Top*top=bottom; 恩,什么结果也没有,这条语句实际上是有歧义(ambiguous)的,编译器会报错:error:`Top'isanambiguousbaseof`Bottom'。其实这两种带有歧义的可能性可以用如下语句加以区分:1 Top*topL=(Left*)bottom;2 Top*topR=(Right*
7、)bottom; 这两个赋值语句执行之后,topL和left指针将指向同一个地址,同样topR和right也将指向同一个地址。精彩文档实用标准文案虚拟继承 为了避免上述Top类的多次继承,我们必须虚拟继承类Top。 1 classTop 2 { 3 public: 4 int a; 5 }; 6 7 classLeft:virtualpublicTop 8 { 9 public:10 int b;11 };12 13 classRight
8、:virtualpublicTop14 {15 public:16 int c;17 };18 19 classBottom:publicLeft,publicRight20 {21 public:22 int d;23 };24 上述代码将产生如下的类层次图(其实这可能正好是你最开始想要的继承方式)。精彩文档实用标准文案 对于程序员来说,这种类层次图显得更加简单和清晰,不过对于一个编译器来说,这就复杂得多了。我们再用
此文档下载收益归作者所有