C++当中的继承(二)

  (五)继承,友元,静态成员

  对于这一部分其实很简单,就是认识一下继承和友元函数的关系,以及继承和静态成员的关系。在一个类当中我们可以设置静态成员以及友元函数。那么我们在基类当中设置的友元函数以及静态成员变量是否可以被继承呢?我们来直接获得结论:

  首先:友元函数不能被继承,其实道理很简单,相信大家都听过一句话:朋友的朋友不一定是我的朋友。设置友元函数可以访问该类当中的所有的成员参数,但是这和我们的派生类有什么关系?并且我们的派生类还保存着我们自己的东西呢!所以道理很简单,友元函数无法被继承要想使用只能进行重新设置。

  其次:静态成员可以被继承。我们需要知道的是,我们设置的静态成员变量或函数会保存在静态区当中。经过继承之后我们的派生类同样可以访问该静态成员变量。那么提出一个小问题:我们应该怎么确定我们创建的同一类型的类有多少个呢?这个时候就可以通过静态成员变量进行记录。我们只需要在基类当中设置一个静态的成员变量即可。每一次调用基类的构造函数的时候都会对我们 的静态成员变量进行++操作,这样不论是创建我们的基类对象还是创建我们的派生类对象都会进行统计,我们这个类型的对象个数也就被统计出来了。代码如下:

  我们会发现代码运行一切正常,无论是基类对象还是派生类对象都进行了统计。

  (六)多继承

  在C++当中还引入了多继承的概念,其实也很容易理解,事务的属性并不是单一的。比如学生可以拥有人的属性还可以拥有青少年的属性。所以在C++当中为了更好的描述我们真实世界的状况就引入了多继承的概念,允许我们的派生类同时继承多个基类。其结构如下:

  多继承的实际使用方法跟我们的普通继承完全相同。同样会产生隐藏,同样需要我们进行指定类进行特定的访问,同样在创建派生类的时候会自动调用我们基类的默认成员函数。但是多继承的导入还会带来很多隐患。

  (七)菱形继承

  菱形继承是我们多继承所带来的最大的一个问题。所谓的菱形继承就是一个类被多个类所继承之后我们的另一个类同时继承我们产生的两个派生类的情况。

  当我们产生该种继承方式的时候就会出现数据冗余和二义性的问题,因为我们会发现在类B和类C当中都继承了类A,所以我们类A当中的数据自然也就复制了一份到我们的类B和类C当中了,那么派生类D在继承类B和类C的时候又会将类B和类C当中的数据复制一份到我们的类D当中。这样的话我们类D当中保存的类A的数据就存在了两份,一份是从类B当中继承得到的,一份是从类C当中继承得到的。这两份数据针对这不同的类A对象,同样也可以保存不同的数据。我们可以通过如下的代码进行测试:

  通过调试我们可以发现,在类D当中的a确实保存了两份。所以为了解决数据冗余跟二义性所带来的问题,我们就引入了虚继承的概念。

  ※虚继承

  所谓的虚继承就是专门应对我们菱形继承所带来的问题所引入的概念。我们需要在菱形继承的中间类明确标注出虚继承的方式即可。

  如下代码所示。实际上的虚继承就是改变了我们数据的存储结构。

  对于我们普通的继承方式来说我们只需要将数据复制一份到我们的派生类当中即可,不需要进行任何的处理。但是针对于我们虚继承的类来说,我们需要生成一张虚函数表。我们同样通过调试的方式进行观察:

  调用内存窗口我们可以发现,对于d对象来说实际上数据在d对象当中是这样进行存储的。首先我们会存储B类,之后存储C类,之后存储D类,最后存储A类。在B类和C类当中的存储方式好像很奇怪,第一个位置有一个很奇怪的数据,第二个位置是我们类当中的成员变量。对于C类同样如此。实际上第一个很奇怪的数据其实是一个地址。我们重新调用一个内存窗口进行查看。

  由于是小端存储结构所以我们需要反过来查证真正的地址。可是我们同样看不太懂呀。那么我们直接进行介绍:这个地址指向的就是我们的虚基表。在虚基表当中我们会保存两个数据,第一个数据我们之后会用到实际上就是虚函数表,在多态章节当中会进行介绍,第二个数据就是我们继承章节需要使用到的主要数据了——记录了一个数值,我们将这个十六进制的数据转换成为十进制的形式:我们可以得到一个数字20.这个数字实际上就是我们B派生类和我们A基类存储位置的偏移量,我们进行验证。用0x004FF8B0加上20刚好等于0x004FF8C4。刚好是我们存储A类的位置。对于C类同样是这样进行存储的,我们进行验证:

  和我们的论述完全一致。

  当引进虚继承之后我们就会发现我们由于菱形继承的所引起的数据冗余和二义性的问题也就随之解决的。因为我们会发现。在D当中A类只存储了一份,也自然不会存在数据冗余跟二义性的问题了。

  (七)继承和组合的概念

  所谓的组合就是在类当中包含另一个类,也就是说创建一个类对象在类的内部,我们可以通过对象进行相应的操作。

  我们会发现不论是使用组合的方式还是使用继承的方式都可以访问到我们A类当中想要的数据。

  那么继承和组合有什么区别呢?我们仔细进行思考会发现:继承其实是is a的关系。比如学生是一个人,具有一个人的所有特征,所以我们可以通过继承的方式获得人的所有的特征,两者所属的是is a学生是一个人的特点。而组合来说实际上是has a的关系,也就是某个事务拥有另一个事务。比如汽车会拥有一个发动机,所以我们就可以在汽车的类当中创建一个发动机的类对象,便于我们在类当中对指定的事务进行访问。实际上我们只需要在特定的实践选择特定的适用对象即可。

  但是如果可以的话我们比较推荐使用组合的方式,因为组合会增加我们程序的内聚成都,而继承的方式增加了我们类与类之间的连接关系,也就是说继承增加了耦合的程度。根据我们软件设计的思想一个优秀的代码应该具有高内聚低耦合的特点才好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿白逆袭记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值