C++之继承

目录

一、继承是什么

二、继承的使用

1、继承的格式

2、继承的使用示例

3、三种继承方式

4、继承方式总结

①private成员

②父类的其他成员在子类中的访问方式

③需要子类访问但不允许类外被访问

④继承方式也可以不显示写

⑤实际中多使用public

三、继承的作用域

1、隐藏的定义

四、基类派生类的赋值转换

1、子类对象可以赋值给父类对象、指针或引用

2、切片的定义

五、默认成员函数

1、默认生成的构造函数

2、默认生成的拷贝构造

3、默认生成的赋值

4、析构函数

六、关于友元和静态成员

1、友元

2、静态成员

七、菱形继承,菱形虚拟继承

1、单继承

2、多继承

3、菱形继承

4、菱形虚拟继承

八、继承和组合

1、什么叫做组合

2、组合与继承的区别与联系


一、继承是什么

说到继承,其实就是将共有的数据和方法提取到一个类中,这个类就叫做父类(或基类),继承的类叫子类(或派生类)

继承体现的是类设计定义层次的复用

比如我们有学生,老师两个类,他们都有姓名,性别,年龄等属性,如果我们定义这两个类,那就会有许多类似的代码,这时候就可以用到C++的继承,可以像上面所说的,将共有的数据和方法提取到一个类中,如下所示:

   

这两个类,除了部分属性外,其他高度相似,所以这时候就可以用到继承这个知识点,给一个公共类person,里面有他们各自相似的属性

 

这时就变为了这种形式, 更加简洁明了


二、继承的使用

1、继承的格式

class A : public B

A类是子类(派生类),B类是父类(基类),public是继承方式

继承方式有:public,protected,private

2、继承的使用示例

将上面所示的教师和学生类,用public继承简单示范下如何使用

3、三种继承方式

三种继承方式和我们之前C++类和对象那里的访问限定符一样,都是有三种,公有(public),保护(protected),私有(private)

而子类的三种继承方式和父类中的三种访问方式相组合,共会有9种组合方式

4、继承方式总结

①private成员

关于父类中的private成员,子类无论用什么继承方式,均为不可见,虽然父类的私有成员也被继承到子类中了,但是C++语法限制子类不论在类内还是类外均无法访问

②父类的其他成员在子类中的访问方式

父类的其他成员在子类中的访问方式,是按照访问限定符和继承方式二者中权限较小的来进行访问的

权限大小排行:private < protected < public

例如:父类中的访问限定符是protected,而子类的继承方式是public,这时父类的其他成员在子类中的访问方式是protected,因为protected权限小于public

③需要子类访问但不允许类外被访问

当需要子类访问但不允许类外被访问时,则父类将需要子类访问的部分定为protected,这样子类继承方式如果是public或protected,这样就可以满足要求

这个需求就是关于protected限定符的由来

④继承方式也可以不显示写

使用class时,默认继承方式private

使用struct时,默认继承方式public

⑤实际中多使用public

在实际中,绝大多数都使用的是public继承,因为另外两种方式的继承类外使用不了,扩展性不强


三、继承的作用域

强调一点:子类和父类是有独立作用域的

所以如果父类子类有同名函数,并且参数不同,并不是函数重载,因为并不在同一个作用域中,此时构成隐藏(成员函数的隐藏,只要函数名相同就构成隐藏)

1、隐藏的定义

当子类父类有同名成员时,子类成员会屏蔽父类对同名成员的直接访问,这种情况就叫做隐藏,也叫重定义(在子类成员函数中,可以用父类::父类成员访问)

比如,person,student两个类,person是父类,student是子类,如果子类有和父类一样的成员,如下所示:

在子类成员函数中,没有特别指定,只会访问子类的成员,如果想访问父类的成员,就需要指定作用域来访问:

如果出现隐藏,就使用上面的方式进行访问,但是在实际继承中,最好还是不要出现这种情况的


四、基类派生类的赋值转换

1、子类对象可以赋值给父类对象、指针或引用

这里父类子类既不是相同类型,也不是隐式类型转换(因为隐式类型转换不能赋值给指针)

 person是父类,student是子类,语法是支持的,是进行了切片

2、切片的定义

至于为什么可以将子类对象赋值给父类对象、指针或引用,我们可以理解为子类成员是大于等于父类成员的,所以父类有的子类都是有的,那么子类给父类赋值时,可以将和父类一样的进行赋值,而父类没有的切除就行,这个行为就叫做切片

上面图可以形象说明,只有成员123赋值即可,成员45切除出去就可以

同理可知,父类对象不能赋值给子类对象


五、默认成员函数

先构造父类,在构造子类

先析构子类,后析构父类

1、默认生成的构造函数

①子类的成员和类和对象一样,内置类型不处理,自定义类型调用它的构造函数

继承父类成员必须要调用父类的构造函数初始化

2、默认生成的拷贝构造

①子类的成员和类和对象一样,内置类型值拷贝,自定义类型调用它的拷贝构造

继承父类成员必须要调用父类的拷贝构造函数初始化

3、默认生成的赋值

和默认构造、拷贝构造相同

4、析构函数

子类和父类的析构函数构成了隐藏

那么一个父类一个子类的析构函数构成隐藏的原因:

由于多态的需要,析构函数被统一处理成了destructtor(),所以会构成隐藏

在子类的析构函数中,不需要显示调用父类的析构函数,在每个子类的析构函数后面,会自动的调用父类的析构函数,这样可以保证先析构子类,后析构父类,不会出现人为的破坏子类父类析构函数进行的先后顺序的情况


补充一个问题:如何让一个类无法被继承?

①如果想让一个类无法被继承,可以将父类构造函数设为私有,子类是不可见的,这样如果有其他类想继承该类,在子类对象实例化时,必须要调用父类的构造函数,而父类的构造函数私有,无法访问,就可以保证让一个类无法被继承

②C++11中有语法支持,在父类后加final关键字即可完成要求

即:class A final,父类是A类,在后面加上final,子类就无法继承了


六、关于友元和静态成员

1、友元

友元关系是不能继承的,例如A是父类,B是子类,父类中有一个友元函数Print(),子类继承父类后和Print()没有任何关系

2、静态成员

若是父类定义了static静态成员,则整个继承的体系中只有一个这样的成员,无论派生多少子类,都只有一个static静态成员


七、菱形继承,菱形虚拟继承

1、单继承

一个子类只有一个直接父类

2、多继承

一个子类有两个或两个以上的直接父类

 例如:子类C有两个直接父类,分别是父类A和父类B,这种继承关系就是多继承

3、菱形继承

菱形继承是多继承的一种特殊情况

A和B类同时继承D类,而C类又继承A和B类,从而构成了菱形继承

菱形继承有数据冗余和二义性的问题存在

数据冗余:C类中有A和B类的,A和B类中又有D类的,会导致C中重复出现两份一样的D类的成员的相关代码,并且在C类调用构造函数,拷贝函数等函数时,也会重复调用两次D类的相同函数,造成空间浪费等问题,从而导致数据冗余问题

二义性:C类继承了A和B类,那A和B类继承的D类的成员,在C类中想访问D类成员,不能明确知道到底是A类的还是B类的,从而形成了二义性问题。二义性问题只能在D类成员前加 A::或B:: 来明确到底是哪个类的. 像截图这种形式

要解决菱形继承的这两个问题,就需要用菱形虚拟继承来解决

4、菱形虚拟继承

 菱形虚拟继承就是在中间的这两个类做以改动,加上virtual,即:

 这样做可以做到访问D类中的成员时,访问的都是同一个成员

注意:在VS环境下,使用菱形虚拟继承后,内存中就不是之前那种D类A类B类的成员挨个存储了,变为了下图所示的情形,内存中变为了A类,B类,C类,最下面才是D类,并且在加virtual的两个类中,他们内存中的第一个位置存储的是一个地址(虚基表),那个地址是此时的这个存储位置距离父类D中成员位置的字节数,可以通过这个地址,来找到父类的成员

在VS环境中,内存的情况就是上面图片所显示的, 地址中存储的就是该位置距离最下方存储的公共的D类成员的字节数,比如说A类和B类都只有一个成员,并且字节数都是4,那么A类所存储的地址中存的数值就应该是20,因为父类成员的位置与该位置中间隔了20个字节的距离

地址中存储的字节数称为距离或偏移量

所以根据这个知识点,我们在计算A类和B类的大小时,还需要加上那个地址的大小

结合上面所说,一般我们不建议设计多继承,尤其是菱形继承,会在代码的复杂度和相关的性能上都有问题


八、继承和组合

1、什么叫做组合

继承上面已经说到了,组合就是下面这种样例:

 

即在B类中的成员类型,用A的类型,这种就叫做组合

2、组合与继承的区别与联系

继承是指每一个派生类都是一个基类对象,比如说铅笔和文具的关系,铅笔是派生类,文具是基类,铅笔是文具,这种关系我们称之为继承关系

而组合是指B类组合了A类,每个B类对象都有A类对象,比如说A类是方向盘,B类是车,车有轮胎,这种关系我们称之为组合关系

如果实际关系中,既可以继承,又可以组合,那么我们优先选择对象组合

继承:依赖关系很强,耦合度高

组合:依赖关系不强,耦合度低

所以我们多使用组合的话,相比较继承,耦合度低,代码的维护性好,不会出现一个类稍做改变,会影响许多类

这就是C++继承的相关知识了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值