【C++】OOP(二):定义基类和派生类

15.2 定义基类和派生类

15.2.1 定义基类

我们首先完成 Quote 类的定义:

#include <string>class Quote {public:Quote() = default;  // 默认构造函数Quote(const std::string &book, double sales_price):bookNo(book), price(sales_price) { }std::string isbn() { return bookNo; }virtual double net_price(std::size_t n) const{ return n * price; }virtual ~Quote() = default; // 对析构函数进行动态绑定private:std::string bookNo;protected:double price = 0.0;
};

对于上面的类定义,新增的概念是 net_price 和析构函数之前新增的 virtual 关键字,以及最后的 protected 访问说明符。

作为继承关系中根节点的类通常都会定义一个虚析构函数。

基类通常都应该定义一个虚析构函数,即使该函数不执行任何实际操作也是如此。

成员函数与继承

派生类可以继承其基类的成员,然而当遇到如 net_price 这样与类型相关的操作时,派生类必须对其重新定义。即,派生类需要对这些操作提供自己的新定义以覆盖从基类继承而来的旧定义。

C++ 中,基类必须将它的两种成员函数分开来:一种是基类希望其派生类进行覆盖的函数,另一种是积累希望派生类直接继承而不要改变的函数。对于前者,基类通常将其定义为虚函数(virtual)。当我们使用指针或引用调用虚函数时,该调用将被动态绑定。根据引用或指针所绑定的对象类型不同,该调用可能执行基类的版本,也可能执行派生类的版本。

基类通过在其成员函数的声明语句之前加上关键字 virtual,使得该函数执行动态绑定。任何构造函数之外的非静态函数都可以是虚函数。关键字 virtual 只能出现在类内部的声明语句之前,而不能用于类外部的函数定义。如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数

成员函数如果没被声明为虚函数,则其解析过程发生在编译时而非运行时。对于 isbn 成员来说这正是我们希望看到的结果。isbn 函数的执行与派生类的细节无关,不管作用于 Quote 对象还是 bulk_quote 对象,isbn 函数的行为都一样。

访问控制与继承

派生类可以继承定义在基类的成员,但派生类的成员函数不一定有权访问从基类继承而来的成员。

和其他使用基类的代码一样,派生类能访问公有成员,但不能访问私有成员。

在基类中还有这样的一类成员,它允许派生类访问而不允许其它用户访问,用**受保护的(protected)**访问运算符说明这样的成员。

15.2.2 定义派生类

派生类必须通过使用类派生列表来明确指出它是从哪个(哪些)基类继承来的(一个派生类可以同时继承多个基类,需要在类派生列表当中指出)。

类派生列表的格式如下:首先是一个冒号,随后紧跟以逗号分隔的基类列表,其中每个基类前面有三种访问说明符的一个:public、protected、private。

派生类必须将其继承而来的成员函数中需要覆盖的那些重新声明,因此,Bulk_quote 类必须包含一个 net_price 成员:

class Bulk_quote: public Quote {public:Bulk_quote() = default;Bulk_quote(const std::string&, double, std::size_t, double);;double net_price(std::size_t) const override;// 👆 覆盖基类的函数版本以实现基于大量购买的折扣政策private:std::size_t min_qty = 0;double discount = 0.0;
};

Bulk_quote 类从它的基类 Quote 继承了 isbn 函数和 bookNo、price 等数据成员(直接继承而不需要 override 的成员不需要在类定义当中重复定义)。此外,它还定义了 net_price 的新版本,同时新增了两个成员 min_qty 和 discount。

派生列表(即:class Bulk_quote: public Quote中冒号后面的部分)中访问说明符的作用是控制派生类从基类继承而来的成员是否对派生类的用户可见

如果一个派生是公有的则基类的公有成员也是派生类接口的组成部分。此外,我们可以将公有派生类型的对象绑定到基类的引用或指针上。因为我们在派生列表中使用了 public,所以 Bulk_quote 的接口隐式地包含 isbn 函数,同时在任何需要 Quote 的引用或指针的地方可以使用 Bulk_quote 的对象。

大多数类只继承自一个类,这种形式的继承称作“单继承”。

派生类中的虚函数

派生类经常(但不总是)覆盖它继承的虚函数。如果没有覆盖基类中的基函数,则该虚函数的行为类似于其它普通成员,派生类直接继承基类的版本。

C++ 11 允许派生类显式地注明它使用某个成员函数覆盖了它继承的虚函数。方法是在函数参数列表或 const 后加上关键字 override。

派生类对象及派生类向基类的类型转换

一个派生类对象包含多个组成部分:一个含有派生类自己定义的(非静态)成员的子对象,以及一个与派生类继承的基类对应的子对象(如果有多个继承的基类,那么这样的子对象也将会有多个)。

因此,一个 Bulk_quote 对象包含四个数据元素:从 Quote 继承来的 bookNo 和 price 数据成员,以及 Bulk_quote 自己定义的 min_qty 和 discount:

其逻辑模型类似于下图:
在这里插入图片描述
因为在派生类对象中含有与基类对应的组成部分,所以我们可以把派生类的对象当成基类对象来使用。并且,我们可以将基类的指针或引用绑定到派生类对象中的基类部分上

Quote item;			// 基类对象
Bulk_quote bulk;	// 派生类对象
Quote *p = &item;	// p 指向 Quote 对象
p = &bulk;			// p 指向 Bulk_quote 对象当中的 Quote 部分
Quote &r = bulk;	// r 绑定到 bulk 的 Quote 部分

上述转换常被称为派生类到基类的(derived-to-base)类型转换。编译器会隐式地执行派生类到基类的转换。

派生类构造函数

尽管在派生类对象中含有从基类继承而来的成员,但派生类不能直接初始化这些成员。和其它创建了基类对象的代码一样,派生类也必须使用基类的构造函数来初始化基类部分

每个类控制它自己的成员初始化过程。

类似于初始化成员的过程,派生类构造函数同样通过构造函数的初始化列表将实参传递给基类的构造函数:

Bulk_quote(const std::string& book, double p, std::size_t qty, double disc):Quote(book, p), min_qty(qty), discount(disc) { }

派生类使用基类的成员

派生类可以访问基类的公有成员(public)和受保护成员(protected)。

继承与静态成员

如果基类定义了一个静态成员,则在整个继承体系中只存在该成员的唯一定义。不论从基类中派生出多少个派生类,对于每个静态成员来说都只存在唯一的实例。

派生类的声明

派生类的声明与派生类的定义是不同的概念。针对声明,派生类的声明与其他类的声明差别不大,声明中包含类名但是不包含它的派生列表。派生列表在定义中给出:

class Bulk_quote;				// 正确👌
class Bulk_quote: public Quote; // 错误❌: 声明中不要给出派生列表

被用作基类的类

如果我们希望将某个类用作基类,则该类必须是已经经过定义的,而非仅仅声明:

class Quote;					// 声明但未定义
class Bulk_quote: public Quote;	// 错误❌: Quote 未定义

这一规定的原因也是显而易见的,派生类中包含并且可以使用它从基类继承而来的成员。为了使用这些成员,派生类需要知道它们是什么。由此隐含的一层意思是,类不能派生它自身。

一个类可以同时是基类也是派生类,由此产生了直接继承和间接继承的关系。

防止继承的发生

C++ 11 标准提供了一种防止继承发生的方式,即在类名后添加关键字 final:

class NoDerived final { /* ... ... ... */ };	//	NoDerived 不能作为基类

15.2.3 类型转换与继承

正如前面我们已经看到过的,可以将基类的指针或引用绑定到派生类对象上。原因在于,派生类在逻辑上可以看作是基类组成部分 + 派生类新添加部分的组合。基类的指针或引用在指向派生类或与派生类绑定时,实际上是指向或绑定到派生类当中的基类部分上。

可以将基类的指针或引用绑定到派生类对象上有一层极为重要的含义:当使用基类的引用(或指针)时,实际上我们并不清楚引用(或指针)所绑定对象的真实类型。该对象可能是基类的对象,也可能是派生类的对象(动态绑定)。

和内置指针一样,智能指针也支持派生类向基类的类型转换,这意味着可以将一个派生类对象的指针存储在一个基类的智能指针内。

静态类型与动态类型

当我们使用存在继承关系的类型时,必须将一个变量或其它表达式的静态类型与该表达式表示对象的动态类型区分开来。

表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型;动态类型则是变量或表达式表示的内存中的对象的类型。动态类型直到运行时才知道

如果表达式既不是引用也不是指针,则它的动态类型永远与静态类型一致。

不存在从基类向派生类的隐式类型转换… …

之所以存在派生类向基类的类型转换是因为每个派生类对象都包含一个基类的部分。派生类向基类的类型转换将直接返回派生类当中包含的基类部分。

然而,由于基类不包含派生类额外新增的部分,因此不存在基类向派生类的隐式类型转换。

… … 在对象之间不存在类型转换

**派生类向基类的自动类型转换只对指针或引用类型有效。**在派生类类型和基类类型之间不存在这样的转换。

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

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

相关文章

软件安装不成功,一直出现“chrome_elf.dll丢失”问题是什么原因?“chrome_elf.dll丢失”要怎么解决和预防?

软件安装遇阻&#xff1a;“chrome_elf.dll丢失”问题全解析与解决方案 在软件安装与运行的过程中&#xff0c;我们时常会遇到各式各样的错误提示&#xff0c;其中“chrome_elf.dll丢失”便是较为常见的一种。这个错误不仅阻碍了软件的正常安装&#xff0c;也给用户带来了不小…

Python爬虫之Scrapy框架基础入门

Scrapy 是一个用于Python的开源网络爬虫框架&#xff0c;它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取&#xff0c;如数据挖掘、监控和自动化测试等。 【1】安装 pip install scrapy安装成功如下所示&#xff1a;…

数据结构_拓扑排序

拓扑排序 &#xff08;所有点按照先后顺序排序&#xff09; 1.先找到入度为0的点&#xff0c;记录之后&#xff0c;删除这个点和它的出边&#xff1b; 2.若有两个可选&#xff0c;随便选择一个 例 a的入度为0,选a [a] 随便选一个 [a,e] 再找入度为0的点 再选c 最后选d 拓…

又细又长的马尾:tail

英语里边有一个单词 tail&#xff0c;意为“尾巴”&#xff0c;这应当是众所周知的事情了。 不过&#xff0c;tail 这条尾巴&#xff0c;并不简单&#xff0c;因为它还是一个词根&#xff0c;也就是说 tail 其实是自由词素。 事实上&#xff0c;tail 最初来自 马尾 这样一个概…

ARM学习(35)单元测试框架以及MinGW GCC覆盖率报告

单元测试框架以及MinGW GCC覆盖率报告 1、单元测试与覆盖率简介 随着代码越写越多,越来越需要注意自测的重要性,基本可以提前解决90%的问题,所以就来介绍一下单元测试,单元测试是否测试充分,需要进行评价,覆盖率就是单元测试是否充分的评估工具。 例如跑过单元测试后,…

前后端分离的项目使用nginx 解决 Invalid CORS request

我是这样打算的&#xff0c;前端用nginx代理&#xff0c;使用80 转443 端口走https 前端的地址就是http://yumbo.top 或https://yumbo.top 后端服务地址是&#xff1a;http://yumbo.top:8081 下面是我的完整配置&#xff0c;功能是正常的&#xff0c;加了注释 user nginx; …

用 Python 格式化器重新定义用户体验

文章目录 摘要引言用户体验优化的核心原则代码格式化工具代码模块详解核心类&#xff1a;CodeFormatter代码格式化方法&#xff1a;format核心逻辑处理使用示例示例输出用户体验设计亮点 QA 环节总结参考资料 摘要 开发者工具的用户体验&#xff08;UX&#xff09;对其使用率和…

如何使mysql数据库ID从0开始编号——以BiCorpus为例

BiCorpus是北京语言大学韩林涛老师研制一款在线语料库网站&#xff0c;可以通过上传tmx文件&#xff0c;实现在线检索功能&#xff0c;程序在github上开源免费&#xff0c;深受广大网友的喜欢。 在使用过程中&#xff0c;我发现我上传的语言资产经历修改后&#xff0c;mysql的…

Tomcat项目本地部署

前言&#xff1a; 除了在idea中将项目启动之外&#xff0c;也可以将项目部署在本地tomcat或者云服务器上&#xff0c;本片文章主要介绍了怎样将项目部署在本地tomcat 下面介绍如何使用Tomcat部署本地项目&#xff1a; 1、本篇文章使用的项目案例为一个聚合项目&#xff0c;ha…

2024-12-14 学习人工智能的Day35 卷积神经网络.阶段项目

卷积神经网络项目实现 关于项目实现的文档说明书&#xff0c;三个要素&#xff1a;数据、模型、训练 1、项目简介。 1.1 项目名称 ​ 基于CNN实现扑克牌花色的小颗粒度分类 1.2 项目简介 ​ 该项目旨在通过卷积神经网络&#xff08;CNN&#xff09;实现扑克的小颗粒度分类…

LabVIEW汽车综合参数测量

系统基于LabVIEW虚拟仪器技术&#xff0c;专为汽车带轮生产中的质量控制而设计&#xff0c;自动化测量和检测带轮的关键参数。系统采用PCIe-6320数据采集卡与精密传感器结合&#xff0c;能够对带轮的直径、厚度等多个参数进行高精度测量&#xff0c;并通过比较测量法判定产品合…

C++编程: 基于cpp-httplib和nlohmann/json实现简单的HTTP Server

文章目录 0. 引言1. 完整实例代码2. 关键实现3. 运行与测试 0. 引言 本文基于 cpp-httplib 和 nlohmann/json 实现简单的 HTTPS Server 实例代码&#xff0c;这两个库均是head-only的。 1. 完整实例代码 如下实例程序修改自example/server.cc #include <httplib.h>#i…

arcGIS使用笔记(无人机tif合并、导出、去除黑边、重采样)

无人机航拍建图之后&#xff0c;通过大疆智图软件可以对所飞行的区域的进行拼图&#xff0c;但是如果需要对拼好的图再次合并&#xff0c;则需要利用到arcGIS软件。下面介绍arcGIS软件在这个过程中常用的操作。 1.导入tif文件并显示的方法&#xff1a;点击“”图标进行导入操作…

FPGA 第十四讲 分频器--偶分频

时间:2024.12.14 时钟对于 FPGA 是非常重要的,但板载晶振提供的时钟信号频率是固定的,不一定满足工程需求,所以使用分频或倍频产生需要的时钟是很有必要的。 一、学习内容 1.分频器 分频器是数字系统设计中最常见的基本电路之一。所谓“分频”,就是把输入信号的频率变成…

python爬虫--小白篇【爬取B站视频】

目录 一、任务分析 二、网页分析 三、任务实现 一、任务分析 将B站视频爬取并保存到本地&#xff0c;经过分析可知可以分为四个步骤&#xff0c;分别是&#xff1a; 爬取视频页的网页源代码&#xff1b;提取视频和音频的播放地址&#xff1b;下载并保存视频和音频&#x…

基于ArqMATH 数据集探索大语言模型在数学问题推理解答中的能力

概述 论文地址&#xff1a;https://arxiv.org/pdf/2404.00344 源码地址&#xff1a;https://github.com/gipplab/llm-investig-mathstackexchange 大规模语言模型&#xff08;LLMs&#xff09;因其解决自然语言任务的能力而备受关注&#xff0c;在某些任务中&#xff0c;其准…

基于ZYNQ 7z010开发板 oled点亮的实现

dc拉高的时候就是发送128字节数据的时候 发送指令dc拉低 模式是00 sck先置低再置高 复位是与开发板上的按键一样都是低有效 25位字节指令 加 3字节的 页地址加起始结束 b0,00,10, timescale 1ns / 1ps module top0(input wire clk ,input wire rst_n,// out…

360极速浏览器不支持看PDF

360安全浏览器采用的是基于IE内核和Chrome内核的双核浏览器。360极速浏览器是源自Chromium开源项目的浏览器&#xff0c;不但完美融合了IE内核引擎&#xff0c;而且实现了双核引擎的无缝切换。因此在速度上&#xff0c;360极速浏览器的极速体验感更佳。 展示自己的时候要在有优…

基于SpringBoot和PostGIS的全球城市信息管理实践

目录 前言 一、业务需求介绍 1、功能思维导图 二、业务系统后台实现 1、Model层实现 2、业务层的实现 3、控制层的实现 三、前端管理业务的实现 1、全球城市列表的实现 2、详情页面实现 3、实际城市定位 四、总结 前言 在全球化和信息化时代背景下&#xff0c;城市作…

《饕餮记》精彩片段(一)

也是无意中看到鲛人脍单元集片段&#xff0c;才去看了这个剧 整体略架空和部分逻辑不是很连贯和完美 精彩点不在于整体和走向和故事线 也不在于大牌明星撑场&#xff0c;因为全场只有安悦溪一个脸熟明星撑场子 而在于每个单元间离奇小故事 和华胥引差不多&#xff0c;属于逻…