C++primer(第五版)第十五章(面向对象程序设计)

news2024/9/20 22:03:08

15.1 OOP:概述

面向对象程序设计(object-oriented programming)的核心思想是数据抽象,继承和动态绑定(个人认为应该是多态,但是书里原话是动态绑定,因此不太确定).

一开始,C++只是C加上一些面向对象特性.C++最初的名称C with Classes 也反映了这个血缘关系                                ——《Effective C++(第三版)》

 C++中,若基类希望其派生类(子类,子孙类)各自定义适合自身的版本,则基类将函数声明成虚函数.(在函数声明前加上关键字virtual).派生类需在内部对所有重新定义的虚函数进行声明.派生类声明时可以加上也可以不必加上virtual关键字.因为一旦基类标注了某函数为虚函数则此函数后续永远都是虚函数.

派生类需通过类派生列表指明从哪个基类继承而来.

class Son: public Father{ //Son类以public方式继承Father类
/*
 * 类实现
 */  
}

子类可以同时继承多个父类,但是不推荐,一次最好是只继承一个父类,但是也可以通过父类去继承其他类来实现多继承.

以下例子说明一次继承多个父类的坏处:

可以看出s1调用speak函数报错,因为Student类没有此函数,因此去父类中寻找,而父类中有两个,无法确定调用哪一个,在下面再次调用时加入作用域后可以确认调用哪个父类的speak函数后不报错.

动态绑定在运行时选择函数的版本,所以动态绑定有时被称为运行时绑定.非虚函数的解析过程发生在编译时而非运行时.

当我们使用基类的引用或是指针调用一个虚函数时发生动态绑定.

 以上例子可以看出同一个函数,我们可以用两个不同类型的对象来调用,且调用结果因对象的类型不同而不同.

15.2定义基类和派生类

15.2.1定义基类

基类通常都应该定义一个虚析构函数,即使该函数 不执行任何实际操作.这点应该不难理解,因为派生类大概率会需要释放比基类更多的资源.

任何构造函数之外的非静态函数都可以是虚函数,但关键字virtual只能出现在类内部的声明语句之前,而不能用于类外部的函数定义.

若我们希望基类的成员不被外部用户使用,而派生类可以访问,则可以使用protected访问运算符来说明这样的成员.

15.2.2定义派生类

派生类需要将继承来的成员函数中需要覆盖的重新声明.派生类经常但不总是覆盖它继承的虚函数.

C++11新标准可以显示地标注覆盖其继承的虚函数,在函数声明的后面加上关键字override.或override标记了没有覆盖已存在的虚函数的函数,则会发生报错.

//以刚刚的类为例
class person :public people {
public:
	virtual void speak() override{  //override在这里
		cout << "hello world!" << endl;
	}
};

我们可以将基类的指针或是引用绑定到派生类对象中的基类部分(反过来不行),因为派生类有基类的成员,但基类不一定有派生类的成员.

每个类控制自己的成员初始化过程,因此派生类需使用基类的构造函数来初始化它的基类部分.除非我们特别指出,否则派生类中的基类部分会执行默认初始化.初始化顺序是先初始化基类部分,然后按照声明顺序依次初始化派生类的成员.

若基类中定义了一个静态成员,那么整个继承体系中只存在该成员的唯一定义.

声明中派生类只包含类名不包含派生列表(继承自).

C++11新标准提供,若基类定义在类名后加上关键字final则可以防止继承的发生.final同样可以用于标记成员函数,使得成员函数不可被覆盖.

15.2.3类型转换与继承

不存在从基类向派生类的隐式类型转换,在对象之间不存在类型转换.

存在派生类向基类的类型转换是因为每个派生类对象都包含一个基类部分(反过来不成立).并且派生类想基类的自动类型转换只对指针或引用类型有效.在派生类类型与基类类型之间不存在这样的转换.

当我们使用一个派生类为基类初始化或是赋值时,只有派生类对象中基类部分会被拷贝,移动,赋值,多余部分会被忽略.

15.3虚函数

一个派生类的函数如果覆盖了某个继承来的虚函数,则形参类型必须和覆盖的基类函数一致.并且返回值也需要与基类函数匹配,除非返回值类型是类本身的指针或是引用.

虚函数可以拥有默认实参,派生类的默认实参最好与基类的保持一致,但不是必须.

使用作用域运算符可以使用指定版本的虚函数,可以参考上面的某个代码.

15.4抽象基类

含有纯虚函数的类是抽象基类,抽象类无法被创建对象,只能被继承.

纯虚函数即在虚函数的函数体位置接上=0即可,并且=0只能出现在类内部的虚函数声明语句处.

//例如
virtual void speak() = 0;

15.5访问控制与继承

继承时使用的访问权限控制符不影响派生类的访问权限,派生类的访问权限值取决于基类中定义成员时,成员所在的访问权限.

继承时使用的访问权限控制符影响的是派生类对象以及派生类的派生类.

友元关系不能被继承.每个类负责控制各自成员的访问权限.

若我们需要改变派生类继承的某个名字的访问级别可以使用using声明.派生类只能对自己可以访问的对象使用using声明.

class people {
protected:
	int age;
};
class person :private people {
public:
	using people::age;
};

15.6继承中的类作用域

派生类的作用域位于基类作用域之外.

派生类能重用定义在其直接基类或间接基类中的名字,此时定义在内层作用域(派生类)的名字将隐藏定义在外层作用域(基类)的名字.简单来说即派生类的成员将隐藏同名的基类成员.

除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义在基类中的名字.

若派生类的成员函数与基类的函数重名,那么将会隐藏基类的函数,即使形参列表不一致.

如果派生类希望基类中的重载函数(这里我们认为重载函数是有多个同名的函数),那么需要覆盖全部版本,或者一个也不覆盖.

也可以使用using声明语句来声明重载的成员,然后再覆盖自己想要重写的某个重载版本函数.这样即可以继承来自基类的多个重载函数,也可以重写某个版本的重载函数并且不必对每个版本都进行覆盖.

15.7构造函数与拷贝控制

 在派生类的构造函数中可以直接实现基类的构造函数.

using不改变构造函数的访问级别.

derived(parms) : base(args) { }

derived:派生类名字

parms:构造函数形参列表

base:基类名字

args:传递给基类构造函数的参数

class people {
protected:
	int age;
	string name;
	people(int a,string n):age(a),name(n){}

};
class person :private people {
public:
	person(int a,string n):people(a,n){}    //注意这行
};

15.8容器与继承

当派生类对象被赋值给基类对象时,其中的派生类部分会被忽略,因此容器和存在继承关系的类型无法兼容.

 我们可以看到,在存储类型为基类的容器中,无论装进去的是基类还是派生类,最终都会变成基类.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/736305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

摆动排序 II · Wiggle Sort II

链接&#xff1a; 题解&#xff1a; 1.先用partition函数&#xff0c;求得n/2的位置的排序 2.然后选取首尾指针&#xff08;奇数选择1和length-1&#xff0c;偶数选择为1和length-2&#xff09;&#xff0c;进行swap交换 3.每次首指针每次2&#xff0c;尾指针每次-2 九章算…

使用 Sa-Token 实现不同的登录模式:单地登录、多地登录、同端互斥登录

一、需求分析 如果你经常使用腾讯QQ&#xff0c;就会发现它的登录有如下特点&#xff1a;它可以手机电脑同时在线&#xff0c;但是不能在两个手机上同时登录一个账号。 同端互斥登录&#xff0c;指的就是&#xff1a;像腾讯QQ一样&#xff0c;在同一类型设备上只允许单地点登…

Spring:Bean生命周期

Bean 生命周期 生命周期 Bean 生命周期是 bean 对象从创建到销毁的整个过程。 简单的 Bean 生命周期的过程&#xff1a; 1.实例化&#xff08;调用构造方法对 bean 进行实例化&#xff09; 2.依赖注入&#xff08;调用 set 方法对 bean 进行赋值&#xff09; 3.初始化&#x…

IDEA使用教程 安装教程

16. Codota 插件 Codota 插件可以根据使用频率优先显示较常用的类和方法。然而&#xff0c;是否使用该插件取决于个人的偏好。有时工具只能作为参考&#xff0c;仍然需要依靠个人记忆来确保准确性。 17. 快速查看类和字段的注释 按下 F2 键可以快速查看某个类或字段的文档注…

编译运行Secure Value Recovery Service v2

下载项目 git clone https://github.com/signalapp/SecureValueRecovery2.git编译 make dockersh报错 修改Dockerfile ARG PROTOC_GEN_GO_GITREV6875c3d7242d1a3db910ce8a504f124cb840c23a RUN go env -w GOPROXYhttps://goproxy.cn,direct RUN go install google.golang.org/p…

阿里云轻量应用服务器和云服务器的区别

阿里云服务器ECS和轻量应用服务器有什么区别&#xff1f;云服务器ECS是明星级云服务器&#xff0c;轻量应用服务器可以理解为简化版的云服务器ECS&#xff0c;轻量适用于单机应用&#xff0c;云服务器ECS适用于集群类高可用高容灾应用&#xff0c;阿里云百科来详细说下阿里云轻…

MachineLearningWu_10_NeuralNetwork

x.1 课程目录 为了开始我们的学习&#xff0c;我们会先列出我们的课程目录&#xff0c;诸如以下&#xff0c; x.2 NN的发展 NN一开始是为了模仿人类大脑&#xff0c;但随着时间的演进&#xff0c;逐渐被使用在各种应用之中&#xff0c; 深度学习DL为何最近几年突飞猛进呢&…

IDEA使用插件绘制UML类图+PlantUML语法讲解

安装 IDEA安装插件 安装完插件记得重启一下IDEA 安装Graphviz&#xff08;亲测win11可以使用&#xff09; 安装完插件之后&#xff0c;还需要安装Graphviz才可以渲染图形。 Graphviz安装包下载地址 安装过程很简单&#xff0c;直接双击或者管理员身份运行即可&#xff0c;注…

高性能内存对象缓存 Memcached

高性能内存对象缓存 Memcached Memcached 概述 一套开源的高性能分布式内存对象缓存系统 所有的数据都存储在内存中 支持任意存储类型的数据 提高网站的访问速度 Memcached 是典型的 C/S 架构&#xff0c;因此需要安装 Memcached 服务端与 Memcached API 客户端。 数据存…

实验三(OSPF)7 8

解题思路&#xff1a; 先配置好路由的环回及规划好IP地址&#xff0c;确保正确&#xff1b; &#xff08;由于r8模拟为运营商&#xff0c;因此r1,r2,r3各写一条缺省指向r8 并测试&#xff09; hub-spoke网络结构&#xff0c;需要在r1-r2-r3建立隧道0配置MGRE-多点通用路由协…

FreeRTOS ~(七)互斥量 ~ (3/3)互斥量的缺陷和递归锁

前情提要 FreeRTOS ~&#xff08;四&#xff09;同步互斥与通信 ~ &#xff08;2/3&#xff09;互斥的缺陷 FreeRTOS ~&#xff08;五&#xff09;队列的常规使用 ~ &#xff08;2/5&#xff09;队列解决互斥缺陷 FreeRTOS ~&#xff08;六&#xff09;信号量 ~ &#xff08;2/…

超详细 | 遗传-粒子群自适应优化算法及其实现(Matlab)

作者在前面的文章中介绍了两种经典的优化算法——遗传算法(GA)和粒子群算法(PSO)&#xff0c;这些智能优化算法解决问题的方式和角度各不相同&#xff0c;都有各自的适用域和局限性&#xff0c;对智能优化算法自身做的改进在算法性能方面得到了一定程度的提升&#xff0c;但算法…

前端如何实现面向对象

交流所记&#xff1a; 面向对象的三要素&#xff1a; 封装&#xff1a;把客观事物封装成抽象的类&#xff0c;并且类可以把自己的数据和方法只让可信的类或者对象操作&#xff0c;对不可信的类或者对象隐藏信息继承&#xff1a;它可以使用现有类的所有功能&#xff0c;并在无…

链上衍生品协议 ProsperEx:探索 RWA 叙事,打造 DeFi 变异黑马

“ProsperEx 本身背靠着具备潜力的链上衍生品赛道&#xff0c;同时也是 RWA 领域早期的布局者之一&#xff0c;其有望成为 Web2 世界与 Web3 世界的早期连接点&#xff0c;并具备广泛且规模性捕获用户的能力。” 从2020年DeFi之夏链上世界迎来了爆发后&#xff0c;链上衍生品赛…

SQL21 浙江大学用户题目回答情况

解法一:left JOIN select t1.device_id,question_id,result from question_practice_detail t1 left JOIN user_profile t2 on t1.device_id t2.device_id where university 浙江大学解法二:子查询 select device_id, question_id, result from question_practice_detail …

Android 性能优化系列:启动优化进阶

文章目录 启动速度优化的本质因素CPU 层面进行速度优化减少程序的指令数降低时钟周期时间降低每条指令的平均时间周期 缓存层面进行速度优化缓存的读写速度缓存的命中率 任务调度层面进行速度优化通过实时进程和普通进程了解任务调度机制原理进程生命周期 CPU 优化合理使用线程…

day67_mybatisplus

今日内容 零、 复习昨日 零、 复习昨日 一、MybatisPlus快速入门 [MyBatis-Plus](简介 | MyBatis-Plus (baomidou.com))&#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 官方…

InnoDB: Waiting for page_cleaner to finish flushing of buffer pool 解决方案

这个是因为linux系统时间&#xff0c;Mysql数据库时间&#xff0c;Mysql日志时间出现不一致导致的。 1、date -R 查询linux系统时间 中国标准时区东八区时区 2、mysql数据库的时间 3、在mysql的配置文件里面&#xff0c;定义好时间&#xff0c;时区一致。 问题解决。

前端Vue自定义商品评价页面单选多选标签tags组件单选多选按钮选择器picker组件

随着技术的发展&#xff0c;开发的复杂度也越来越高&#xff0c;传统开发方式将一个系统做成了整块应用&#xff0c;经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改&#xff0c;造成牵一发而动全身。 通过组件化开发&#xff0c;可以有效实现…