C++继承

1.继承是什么

继承是什么:
继承是面向对象程序设计、使得代码可以复用的重要手段,它允许程序员在保持原有特性的基础上进行扩展,增加功能,这样产生的新类,称之为派生类

继承的目的:
让子类继承和复用父类定义的成员和方法、继承下来的变量是独立的、各自拥有各自的内存空间

2.继承的定义格式

在这里插入图片描述

3.继承方式和访问限定符

在这里插入图片描述

1.由上表可知,子类的访问方式=min(基类的访问方式,继承方式) [public>protected>private]

2.基类private成员,在子类中都不可见(继承了,只是在语法上无法访问),调用父类的方法还是可以访问

3.使用关键字class时默认的继承方式为private,使用struct时默认的继承方式是public,建议显示的写出继承方式

4.基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。

5.实际运用中,一般都是使用public继承,很少并且不提倡用protected和private继承,因为这两种继承下来的成员都
只能在子类的类里面使用,实际中扩展延伸性不强

在这里插入图片描述

4.基类和派生类对象赋值

1.派生类对象可以赋值给基类的的对象/指针/引用,这种方式叫做切片或者切割。即将子类中父类拿部分切下来,赋值过去

2.基类对象不能赋值给派生类对象
类似于:参数是单向迭代器时,双向的可以传入,是双向迭代器的时候,单向的不可传入

3.基类的指针可以通过强转类型转换赋值给派生类的指针,但是必须是基类的指针指向派生类对象时才是安全的

4.赋值兼容关系,只有public继承才存在
比如:子类是保护继承的,而父类是公有的,继承下来后,再赋值回去,父类就变成公有的了,这是不符合语义的

在这里插入图片描述
在这里插入图片描述

5.继承之中的作用域

1.在继承体系中基类和派生类都有独立的作用域(即可以定义同名变量)

2.子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种叫做隐藏,也叫做重定义
类似于全局变量和局部变量同名,就近使用局部变量。
在子类成员函数中,可以使用基类::基类成员 显示访问

3.需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏

4.注意在实际中在继承体系里面最好不要定义同名的成员

在这里插入图片描述

6.派生类的默认成员函数

1.构造函数
派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用
在这里插入图片描述
在这里插入图片描述
2.拷贝构造
派生类的拷贝构造函数,必须调用基类的拷贝构造完成基类的拷贝初始化
在这里插入图片描述
3.赋值运算符重载
派生类的operator= 必须调用基类的operator = 完成基类的赋值
在这里插入图片描述
4.析构函数
派生类的析构函数会在被调用完成后,自动调用基类的析构函数清理基类成员。
因为这样才能保证派生类对象,先清理派生类成员的顺序,再清理基类成员的顺序
如果自己显示调用,存在父类先析构问题,不符合语法规则,因此编译器自己调用
在这里插入图片描述

5.派生类对象的初始化先调用基类构造,再调用派生类构造
成员初始化的顺序,和定义的顺序没有关系,和声明的顺序有关系
所以是先初始化基类的构造函数
在这里插入图片描述
6.派生类对象析构清理,先调用派生类析构,再调用基类的析构

7.继承与友元

友元关系不能继承,也就是说基类友元函数不能访问子类私有和保护成员
在这里插入图片描述

8.继承与静态成员

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。
无论派生出对少个子类,都只有一个static成员实例
在这里插入图片描述

9.菱形继承和菱形虚拟继承

菱形继承是C++继承设计的一个缺陷,由于时代背景等原因,这个缺陷一直没有被去除

9.1是什么

1.单继承
一个子类只有一个直接父类时,称这个继承关系为单继承
在这里插入图片描述
2.多继承
一个子类有两个或以上直接父类时,称这个继承关系为多继承
在这里插入图片描述
3.菱形继承
菱形继承是多继承的一种特殊情况
在这里插入图片描述

9.2菱形继承的问题

从上面的模型可知,菱形继承有数据冗余二义性的问题
在这里插入图片描述
在这里插入图片描述

9.3虚拟继承

虚拟继承可以解决数据的二义性和数据冗余的问题,在继承的时候使用虚拟继承即可,需要注意的是虚拟继承不要在其它的地方使用
虚拟继承的关键字:virtual
虚拟继承在一定程度是哪个会造成性能损失,因为需要先找偏移量再找虚基类(和双端队列的下标访问需要进行多次解引用造成下标访问效率低下的原因类似)
在这里插入图片描述

9.4虚拟继承的原理

D对象将A放到了对象组成的最下面,这个A同属于B和C,这样就解决了数据的冗余和二义性

那么B和C是如何找到A的呢?
B和C之中分别有一个虚基表指针,这个指针指向虚基表,虚基表之中保存着偏移量,通过偏移量既可以找到共有的A
在这里插入图片描述
为什么D中的B和C要去寻找自己的A?
这是因为切片赋值时需要去寻找B或者C的A才能赋值过去
在这里插入图片描述
在这里插入图片描述

10.总结

10.1为什么说多继承是C++的一个坑

1.C++语法复杂,多继承就是一个体现,有了多继承就存在菱形继承,有了菱形继承就有了菱形虚拟继承,底层实现就很复杂。一般不建议设计出多继承(IO流文件就是多继承)。当然也不建议设计出菱形继承,否则在复杂度以及性能上都会有问题

2.多继承可以当作是C++的缺陷之一、很多后来的OO(面向对象)语言都没有多继承,因为C++已经趟过雷了

10.2组合和继承的比较

1.public继承是一种 is -a 关系,即每个派生类对象都有一个基类对象
比如:狗是一种动物,描述狗的类,可以继承描述动物的类

2.组合是一种 has -a的关系。比如假设B组合了A,每个B对象都有一个A对象
比如:轮胎、方向盘组成车
在这里插入图片描述
3.继承方式中、基类的细节子类可见,是白箱复用。在一定程度上破坏了基类的封装,基类的改变,对子类有很大的影响。基类和子类之间的耦合性很强

4.组合方式中,组合对象的内部是不可见的,即黑箱复用。并且组合类之间没有很强的依赖关系,耦合度较低

5.实际中,应该尽量多去使用组合,因为组合符合高内聚(自己很独立)、低耦合的思想(不同类之间约松散约好)。组合代码的维护性更好。
但是适合用继承的还是要选择继承,比如多态的实现必须要继承。

6.符合is -a关系的用继承、符合 has -a关系的用组合、都符合选择组合

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值