当前位置: 首页 > news >正文

C++ 多态性——纯虚函数与抽象类

抽象类是一种特殊的类,它为一个类族提供统一的操作界面。抽象类是为了抽象和设计的目的而建立的。可以说,建立抽象类,就是为了通过它多态地使用其中的成员函数。抽象类处于类层次的上层,一个抽象类自身无法实例化,也就是说我们无法定义一个抽象类的对象,只能提供继承机制,生成抽象类的非抽象派生类,然后再实例化。

1.纯虚函数

在基类中声明和不同的派生类中具有相同原型的函数,并将它们声明为虚函数,此时,派生类中和基类中名字相同的函数就会被覆盖掉,然后通过基类的指针调用这些函数时,派生类的相应函数将被实际调用。然而,基类并不知道该如何处理通过基类的指针调用来的派生类函数,无法给出有意义的实现。对于这种在基类中无法实现的函数,可以在基类中只说明函数原型来规定整个类族的统一接口形式,而在派生类中再给出这些函数的实现,纯虚函数来实现这一功能。

纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容,要求各派生类根据实际需求给出各自的定义。

纯虚函数的声明格式为:

virtual 函数类型 函数名(参数表)=0;

实际上,它与一般虚函数成员的原型在书写格式上的不同就在于后面加了“=0”。

声明为纯虚函数之后,基类中就可以不再给出函数的实现部分。纯虚函数的函数体由派生类给出。

【注意】

(1)基类中仍然允许对纯虚函数给出实现,但即使给出实现,也必须由派生类覆盖,否则无法实例化。例如:

#include<iostream>
using namespace std;class B
{
public:virtual void fun() = 0//纯虚函数在基类中实现{cout << "显示基类B" << endl;}
};class D :public B
{
public:virtual void fun() = 0;
};int main()
{D d;d.fun();return 0;
}

以上代码编译错误,原因是:
在这里插入图片描述
将代码修改之后如下:

class B
{
public:virtual void fun() = 0//派生类对基类中的纯虚函数进行覆盖{cout << "显示基类B" << endl;}
};class D :public B
{
public:virtual void fun(){cout << "显示派生类D" << endl;}
};int main()
{D d;d.fun();return 0;
}

运行结果:
在这里插入图片描述

(2)在基类中对纯虚函数定义的函数体的调用,必须通过“基类名::函数名(参数表)”的形式。

(3)如果将基类析构函数声明为纯虚函数,必须给出它的实现,因为派生类的析构函数体执行完后需要调用基类的纯虚函数。

class B
{
public:B(){cout << "基类B的构造函数" << endl;}virtual~B() = 0//声明B类的析构函数为纯虚函数并实现{cout << "基类B的析构函数" << endl;}virtual void fun() = 0;//声明fun为纯虚函数
};class D :public B
{
public:D(){cout << "派生类D的构造函数" << endl;}virtual ~D(){cout << "派生类D的析构函数" << endl;}virtual void fun(){cout << "显示派生类D" << endl;}
};int main()
{D d;return 0;
}

运行结果:
在这里插入图片描述
(4)纯虚函数不同于函数体为空的虚函数:纯虚函数根本就没有函数体,而空的虚函数的函数体为空;纯虚函数所在的类是抽象类,不能直接进行实例化,而函数体为空的虚函数所在的类是可以实例化的。它们共同的特点是都可以派生出新的类,然后在新的类中给出虚函数新的实现,而且这种新的实现具有多态特征。

2.抽象类

带有纯虚函数的类是抽象类。 抽象类的主要作用是通过它为一个类族建立一个公共的接口,使它们能够更有效地发挥多态特性。抽象类声明了一个类族派生类的共同接口,而接口的完整实现,即纯虚函数的函数体,需要派生类自己定义。

抽象类派生出新的类之后,如果派生类给出所有纯虚函数的函数实现,这个派生类就可以自己定义对象,因而不再是抽象类;反之,如果派生类没有给出全部纯虚函数的实现,这时派生类仍然是一个抽象类。

抽象类不能实例化,即不能定义一个抽象类的对象,但是可以定义一个抽象类的指针和引用。通过指针和引用,就可以指向并访问派生类的对象,进而访问派生类的成员,这种访问具有多态特征。

【例】抽象类举例

class A//基类A定义
{
public:virtual void display()const = 0;//声明为纯虚函数};class B :public A//公有派生类B定义
{
public:virtual void display()const//覆盖基类的虚函数{cout << "显示类B" << endl;}
};class C :public B//公有派生类C定义
{
public:virtual void display()const//覆盖基类的虚函数{cout << "显示类C" << endl;}
};void fun(A* p)//参数为指向基类A的对象的指针
{p->display();//"对象指针->成员名"
}int main()
{B b;//定义直接基类为A类的派生类B的对象C c;//定义直接基类为B类的派生类C的对象fun(&b);//用直接基类为A类的派生类B对象的指针调用fun函数fun(&c);//用直接基类为B类的派生类C对象的指针调用fun函数return 0;
}

运行结果:
在这里插入图片描述
分析:
程序中类A,B,C属于同一个类族,抽象类A通过纯虚函数为整个类族提供了通用的外部接口语义。通过公有派生而来的子类B,C给出了纯虚函数的具体实现,因此子类B,C是非抽象类,可以定义派生类的对象,同时根据赋值兼容规则,抽象类A的指针也可以指向任何一个派生类的对象。在fun函数中通过基类A的指针p就可以访问到p指向的派生类B,C的对象成员。这样就实现了对同一类族中的对象进行统一处理的多态。

而且,程序中派生类的虚函数可以不用virtual关键字显式说明,因为它们与基类的纯虚函数具有相同的名称、参数及返回值,由系统自动判断为虚函数。在派生类display函数原型声明中使用virtual也没有错的。

相关文章:

C++ 多态性——纯虚函数与抽象类

抽象类是一种特殊的类&#xff0c;它为一个类族提供统一的操作界面。抽象类是为了抽象和设计的目的而建立的。可以说&#xff0c;建立抽象类&#xff0c;就是为了通过它多态地使用其中的成员函数。抽象类处于类层次的上层&#xff0c;一个抽象类自身无法实例化&#xff0c;也就…...

小程序如何使用防抖和节流?

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;都是用来优化函数执行频率的技术&#xff0c;特别在处理用户输入、滚动等频繁触发的情况下&#xff0c;它们可以有效减少函数的执行次数&#xff0c;从而提升性能和用户体验。但它们的工作方式和应…...

计算机三级网络技术(持续更新)

BGP考点 A S&#xff1a;自治系统 BGP: Border Gateway Protocol&#xff08;当前使用的版本是 BGP-4&#xff09;外部网关协议 动态路由协议可以按照工作范围分为IGP以及EGP。IGP工作在同一个AS内&#xff0c;主要用来发现和计算路由&#xff0c;为AS内提供路由信息的交换&…...

Django Rest_Framework(二)

文章目录 1. http请求响应1.1. 请求与响应1.1.1 Request1.1.1.1 常用属性1&#xff09;.data2&#xff09;.query_params3&#xff09;request._request 基本使用 1.1.2 Response1.1.2.1 构造方式1.1.2.2 response对象的属性1&#xff09;.data2&#xff09;.status_code3&…...

Kotlin~Visitor访问者模式

概念 将数据结构和操作分离&#xff0c;使操作集合可以独立于数据结构变化。 角色介绍 Visitor&#xff1a;抽象访问者&#xff0c;为对象结构每个具体元素类声明一个访问操作。Element&#xff1a;抽象元素&#xff0c;定义一个accept方法ConcreteElement&#xff1a;具体元…...

LVS-DR模式集群构建过程演示

一、工作原理 LVS的工作原理 1.当用户向负载均衡调度器&#xff08;Director Server&#xff09;发起请求&#xff0c;调度器将请求发往至内核空间 2.PREROUTING链首先会接收到用户请求&#xff0c;判断目标IP确定是本机IP&#xff0c;将数据包发往INPUT链 3.IPVS是工作在IN…...

UML-A 卷-知识考卷

UML-A 卷-知识考卷 UML有多少种图&#xff0c;请列出每种图的名字&#xff1a; 常用的几种UML图&#xff1a; 类图&#xff08;Class Diagram&#xff09;&#xff1a;类图是描述类、接口、关联关系和继承关系的图形化表示。它展示了系统中各个类之间的静态结构和关系。时序…...

BpBinder与PPBinder调用过程——Android开发Binder IPC通信技术

在Android系统中&#xff0c;进程间通信&#xff08;IPC&#xff09;是一个非常重要的话题。Android系统通过Binder IPC机制实现进程间通信&#xff0c;而Binder IPC通信技术则是Android系统中最为重要的进程间通信技术之一。本文将介绍Binder IPC通信技术的原理&#xff0c;并…...

篇十五:模板方法模式:固定算法的步骤

篇十五&#xff1a;"模板方法模式&#xff1a;固定算法的步骤" 设计模式是软件开发中的重要知识&#xff0c;模板方法模式&#xff08;Template Method Pattern&#xff09;是一种行为型设计模式&#xff0c;用于定义一个算法的骨架&#xff0c;将算法中一些步骤的具…...

web-ssrf

目录 ssrf介绍 以pikachu靶场为例 curl 访问外网链接 利用file协议查看本地文件 利用dict协议扫描内网主机开放端口 file_get_content 利用file协议查看本地文件&#xff1a; fsockopen() 防御方式: ssrf介绍 服务器端请求伪造&#xff0c;是一种由攻击者构造形成…...

【HarmonyOS】【续集】实现从视频提取音频并保存到pcm文件功能(API6 Java)

【关键字】 视频提取类Extractor、视频编解码、保存pcm文件、getAudioTime 【背景和问题】 上篇中介绍了从视频提取音频并保存到pcm文件功能&#xff0c;请参考文档&#xff1a;https://developer.huawei.com/consumer/cn/forum/topic/0209125665541017202?fid0101591351254…...

MySQL为什么要使用 B+Tree 作为索引结构?

MySQL为什么要使用 BTree 作为索引结构&#xff1f; 基本情况 常规的数据库存储引擎 &#xff0c;一般都是采用 B 树或者 B树来实现索引的存储。B树是一种多路平衡树&#xff0c;用这种存储结构来存储大量数据&#xff0c;它的整个高度 会相比二叉树来说 &#xff0c;会矮很多…...

Three.js阴影

目录 Three.js入门 Three.js光源 Three.js阴影 使用灯光后&#xff0c;场景中就会产生阴影。物体的背面确实在黑暗中&#xff0c;这称为核心阴影&#xff08;core shadow&#xff09;。我们缺少的是落下的阴影&#xff08;drop shadow&#xff09;&#xff0c;即对象在其他…...

VSCode Remote-SSH (Windows)

1. VSCode 安装 VSCode 2. 安装扩展 Remote SSH Getting started Follow the step-by-step tutorial or if you have a simple SSH host setup, connect to it as follows: Press F1 and run the Remote-SSH: Open SSH Host… command.Enter your user and host/IP in the …...

现代C++中的从头开始深度学习【1/8】:基础知识

一、说明 提及机器学习框架与研究和工业的相关性。现在很少有项目不使用Google TensorFlow或Meta PyTorch&#xff0c;在于它们的可扩展性和灵活性。也就是说&#xff0c;花时间从头开始编码机器学习算法似乎违反直觉&#xff0c;即没有任何基本框架。然而&#xff0c;事实并非…...

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限&#xff08;四表联查&#xff09;数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…...

SpringWeb项目核心功能总结

SpringWeb项目核心功能总结 文章目录 SpringWeb项目核心功能总结1.浏览器与Java程序的连接&#xff08;个人偏好使用RequestMapping&#xff09;2.参数的传入3.结果的返回请求转发和请求重定向的区别 核心功能用到的注解&#xff1a; RestControllerControllerResponseBodyRequ…...

Django------信号

Django 框架包含了一个信号机制&#xff0c;它允许若干个发送者&#xff08;sender&#xff09;通知一组接收者&#xff08;receiver&#xff09;某些特定操作或事件(events)已经发生了&#xff0c; 接收者收到指令信号(signals)后再去执行特定的操作。本文主要讲解Django信号(…...

HTML5 中新增了哪些表单元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTML5 中新增了的表单元素⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚…...

[考研机试] KY20 完数VS盈数 清华大学复试上机题 C++实现

描述 一个数如果恰好等于它的各因子(该数本身除外)子和&#xff0c;如&#xff1a;6321。则称其为“完数”&#xff1b;若因子之和大于该数&#xff0c;则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。 输入描述&#xff1a; 题目没有任何输入。 输出描述&#…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...