C++学习教程从零开始(十一)(中)——类的相关知识.docx

C++学习教程从零开始(十一)(中)——类的相关知识.docx

  1. 1、本文档共14页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
C++学习教程从零开始(十一)(中)——类的相关知识多重继承  这里有个有趣的问题,如下:  struct A { long a, b, c; char d; }; struct B : public A { long e, f; };  上面的B::e和B::f映射的偏移是多少?不同的编译器有不同的映射结果,对于派生的实现,C++并没有强行规定。大多数编译器都是让B::e映射的偏移值为16(即A的长度,关于自定义类型的长度可参考《C++从零开始(九)》),B::f映射20。这相当于先把空间留出来排列父类的成员变量,再排列自己的成员变量。但是存在这样的语义——西红柿即是蔬菜又是水果,鲸鱼即是海洋生物又是脯乳动物。即一个实例既是这种类型又是那种类型,对于此,C++提供了多重派生或称多重继承,用“,”间隔各父类,如下:  struct A { long A_a, A_b, c; void ABC(); }; struct B { long c, B_b, B_a; void ABC(); };  struct AB : public A, public B { long ab, c; void ABCD(); };  void A::ABC() { A_a = A_b = 10; c = 20; }  void B::ABC() { B_a = B_b = 20; c = 10; }  void AB::ABCD() { A_a = B_a = 1; A_b = B_b = 2; c = A::c = B::c = 3; }  void main() { AB ab; ab.A_a = 3; ab.B_b = 4; ab.ABC(); }  上面的结构AB从结构A和结构B派生而来,即我们可以说ab既是A的实例也是B的实例,并且还是AB的实例。那么在派生AB时,将生成几个映射元素?照前篇的说法,除了AB的类型定义符“{}”中定义的AB::ab和AB::c以外(类型均为long AB::),还要生成继承来的映射元素,各映射元素名字的修饰换成AB::,类型不变,映射的值也不变。因此对于两个父类,则生成8个映射元素(每个类都有4个映射元素),比如其中一个的名字为AB::A_b,类型为long A::,映射的值为4;也有一个名字为AB::B_b,类型为long B::,映射的值依旧为4。注意A::ABC和B::ABC的名字一样,因此其中两个映射元素的名字都为AB::ABC,但类型则一个为void( A:: )()一个为void( B:: )(),映射的地址分别为A::ABC和B::ABC。同样,就有三个映射元素的名字都为AB::c,类型则分别为long A::、long B::和long AB::,映射的偏移值依次为8、0和28。照前面说的先排列父类的成员变量再排列子类的成员变量,因此类型为long AB::的AB::c映射的值为两个父类的长度之和再加上AB::ab所带来的偏移。  注意问题,上面继承生成的8个映射元素中有两对同名,但不存在任何问题,因为它们的类型不同,而最后编译器将根据它们各自的类型而修改它们的名字以形成符号,这样连接时将不会发生重定义问题,但带来其他问题。ab.ABC();一定是ab.AB::ABC();的简写,因为ab是AB类型的,但现在由于有两个AB::ABC,因此上面直接书写ab.ABC将报错,因为无法知道是要哪个AB::ABC,这时怎么办?  回想本文上篇提到的公共、保护、私有继承,其中说过,公共就表示外界可以将子类的实例当作父类的实例来看待。即所有需要用到父类实例的地方,如果是子类实例,且它们之间是公共继承的关系,则编译器将会进行隐式类型转换将子类实例转换成父类实例。因此上面的ab.A_a = 3;实际是ab.AB::A_a = 3;,而AB::A_a的类型是long A::,而成员操作符要求两边所属的类型相同,左边类型为AB,且AB为A的子类,因此编译器将自动进行隐式类型转换,将AB的实例变成A的实例,然后再计算成员操作符。  注意前面说AB::A_b和AB::B_b的偏移值都为4,则ab.A_b = 3;岂不是等效于ab.B_b = 3;?即使按照上面的说法,由于AB::A_b和AB::B_b的类型分别是long A::和long B::,也最多只是前者转换成A的实例后者转换成B的实例,AB::A_b和AB::B_b映射的偏移依旧没变啊。因此变的是成员操作符左边的数字。对于结构AB,假设先排列父类A的成员变量再排列父类B的成员变量,则AB::B_b映射的偏移就应该为16(结构A的长度加上B::c引入的偏移),但它实际映射为4,因此就将成员操作符左侧的地址类型的数字加上12(结构A的长度)。而对于AB::A_

文档评论(0)

整理王 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档