第13章 类继承

13.1 一个简单的基类

从一个类派生出另一个类时,原始类称为基类,继承类称为派生类。
在这里插入图片描述
(冒号指出RatedPlayer类的基类是TableTennisplayer类,这是一个公有基类)
使用公有派生,基类的公有成员将成为派生类的公有成员;基类的私有部分也将成为派生类的一部分,但只能通过基类的公有和保护方法访问。

  • 派生类对象存储类基类的数据成员(派生类继承了基类的实现)

  • 派生类对象可以使用基类的方法(派生类继承了基类的接口)

  • 派生类需要添加自己的构造函数

  • 派生类可以根据需要添加额外的数据成员和成员函数

派生类不能直接访问基类的私有成员,必须通过基类方法进行访问,也就是说,派生类构造函数必须使用基类构造函数。
在这里插入图片描述
在这里插入图片描述
(调用派生类构造函数时可以输入基类构造函数的参数)
如果不调用基类构造函数,程序将使用默认的基类构造函数。
派生类构造函数:
在这里插入图片描述
在这里插入图片描述
要使用派生类,程序必须要能够访问基类声明。(可以将两个类放到一个头文件中)

派生类对象可以使用基类的方法,条件是方法不是私有的。
另外,基类指针可以在不进行显式类型转换的情况下指向派生类对象,基类引用可以在不进行显式类型转换的情况下引用派生类对象。(不过基类指针只能用于调用基类方法,不能调用派生类新增的方法,也不可以将基类对象和地址赋给派生类引用和指针)
对于形参为基类的引用,他可以指向基类也可以指向派生类,也就是说虽然他的输入类型是基类,但是输入的是派生类也是可以的。
在这里插入图片描述

13.2 继承:is-a关系

公有继承:它建立一种is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生对象执行。也就是所有基类的方法派生类都可以使用。通常它们是同一种属性的类,拥有相同的特征描述。

13.3 多态公有继承

多态:同一个方法在派生类和基类的行为是不同的,也就是说方法的行为应取决于调用该方法的对象,同一个方法的行为随上下文而异。

实现机制:

  • 在派生类中重新定义基类的方法
  • 使用虚方法(关键字:virtual(用在原型中不需要用在定义中))

如果没有使用virtual,程序将根据引用类型或指针类型选择方法,如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法。
在这里插入图片描述
在这里插入图片描述
在派生类方法中,标准技术是使用作用域解析运算符来调用基类方法(当在派生类中重新定义时需要,不重新定义不需要)。
在这里插入图片描述

13.4 静态联编和动态联编

将源代码中的函数调用解释为执行特定的函数代码块被称为函数名联编(函数名与函数代码相关联)。
在编译过程中进行联编被称为静态联编,又称早期联编。然而,虚函数是使这项工作变得困难,使用哪个函数不能在编译时确定,因为编译器不知道用户将选择哪种类型的对象。编译器必须生成能够在程序运行时选择正确的虚方法的代码,这被称为动态联编,又称晚期联编。

编译器处理虚函数的方法:给每个对象添加一个隐藏成员,隐藏成员中保存一个指向函数地址数组的指针,这种数组称为虚函数表。虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。
在这里插入图片描述

  • 构造函数不能是虚函数
  • 析构函数应当是虚函数,除非类不用做基类
  • 友元不能是虚函数,因为友元不是类成员,而只有成员才能是虚函数
  • 如果派生类没有重新定义函数,将使用该函数的基类版本
  • 如果派生类中重载新定义函数,将不是使用相同的函数特征覆盖基类声明,而是隐藏同名的基类方法,不管参数特征标如何。

如果重新定义继承的方法,应确保与原来的原型完全相同,但如果返回类型是基类引用或指针,则可以修改为指向派生类的引用或指针,这种特性被称为返回类型协变。
如果基类声明被重载了,则应在派生类中重新定义所有的基类版本。

13.5 访问控制:protected

protected与private相似,在类外只能用公有类成员来访问protected部分中的类成员。不过,派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。对于外部世界来说,保护成员的行为与私有成员相似,但对于派生类来说,保护成员的行为与公有成员相似。
最好对类数据成员采用私有访问控制,不要使用保护访问控制,同时通过基类方法使派生类能够访问基类数据。

13.6抽象基类

抽象类必须至少要包含一个纯虚函数,纯虚函数声明的结尾处为=0。
纯虚函数一般只提供了接口,并不会做具体实现(虽然可以),实现由它的派生类去重写。抽象类不能被实例化(不能创建对象),通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。简言之,ABC描述的是至少使用一个纯虚函数的接口,从ABC派生出的类将根据派生类的具体特征,使用常规虚函数来实现这种接口。

13.7 继承和动态内存分配

派生类不使用new:
需要析构函数、复制构造函数和赋值运算符
派生类使用new:
必须为派生类定义显示析构函数、复制构造函数和赋值运算符
在这里插入图片描述

13.8 类设计回顾

默认构造函数:默认构造函数要么没参数,要么所有的参数都有默认值。如果没有定义任何构造函数,编译器将定义默认构造函数。如果派生类构造函数的成员初始化列表中没有显式调用基类构造函数,则编译器将使用基类的默认构造函数来构造派生类对象的基类部分。如果定义了某种构造函数,编译器将不会定义默认构造函数。

复制构造函数:复制构造函数接受其所属类的对象作为参数。
在这里插入图片描述

赋值运算符:默认的赋值运算符用于处理同类对象之间的赋值。如果语句创建新的对象则使用初始化,如果语句修改已有对象的值则是赋值。(不能被继承)
在这里插入图片描述
构造函数:创建新的对象,其他类方法只是被现有的对象调用。
析构函数:一定要定义显式析构函数来释放类构造函数使用new分配的所有内存,并完成类对象所需的任何特殊的清理工作。对于基类,即使他不需要析构函数,也应提供一个虚析构函数。
转换:使用一个参数就可以调用的构造函数定义了从参数类型到类类型转换。(直接赋值)
在这里插入图片描述
在这里插入图片描述
编写使用对象作为参数时,应按引用而不是按值来传递对象。
在这里插入图片描述
(返回引用有&)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值