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++ 多态性——纯虚函数与抽象类
抽象类是一种特殊的类,它为一个类族提供统一的操作界面。抽象类是为了抽象和设计的目的而建立的。可以说,建立抽象类,就是为了通过它多态地使用其中的成员函数。抽象类处于类层次的上层,一个抽象类自身无法实例化,也就…...
小程序如何使用防抖和节流?
防抖(Debounce)和节流(Throttle)都是用来优化函数执行频率的技术,特别在处理用户输入、滚动等频繁触发的情况下,它们可以有效减少函数的执行次数,从而提升性能和用户体验。但它们的工作方式和应…...
计算机三级网络技术(持续更新)
BGP考点 A S:自治系统 BGP: Border Gateway Protocol(当前使用的版本是 BGP-4)外部网关协议 动态路由协议可以按照工作范围分为IGP以及EGP。IGP工作在同一个AS内,主要用来发现和计算路由,为AS内提供路由信息的交换&…...
Django Rest_Framework(二)
文章目录 1. http请求响应1.1. 请求与响应1.1.1 Request1.1.1.1 常用属性1).data2).query_params3)request._request 基本使用 1.1.2 Response1.1.2.1 构造方式1.1.2.2 response对象的属性1).data2).status_code3&…...
Kotlin~Visitor访问者模式
概念 将数据结构和操作分离,使操作集合可以独立于数据结构变化。 角色介绍 Visitor:抽象访问者,为对象结构每个具体元素类声明一个访问操作。Element:抽象元素,定义一个accept方法ConcreteElement:具体元…...
LVS-DR模式集群构建过程演示
一、工作原理 LVS的工作原理 1.当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间 2.PREROUTING链首先会接收到用户请求,判断目标IP确定是本机IP,将数据包发往INPUT链 3.IPVS是工作在IN…...
UML-A 卷-知识考卷
UML-A 卷-知识考卷 UML有多少种图,请列出每种图的名字: 常用的几种UML图: 类图(Class Diagram):类图是描述类、接口、关联关系和继承关系的图形化表示。它展示了系统中各个类之间的静态结构和关系。时序…...
BpBinder与PPBinder调用过程——Android开发Binder IPC通信技术
在Android系统中,进程间通信(IPC)是一个非常重要的话题。Android系统通过Binder IPC机制实现进程间通信,而Binder IPC通信技术则是Android系统中最为重要的进程间通信技术之一。本文将介绍Binder IPC通信技术的原理,并…...
篇十五:模板方法模式:固定算法的步骤
篇十五:"模板方法模式:固定算法的步骤" 设计模式是软件开发中的重要知识,模板方法模式(Template Method Pattern)是一种行为型设计模式,用于定义一个算法的骨架,将算法中一些步骤的具…...
web-ssrf
目录 ssrf介绍 以pikachu靶场为例 curl 访问外网链接 利用file协议查看本地文件 利用dict协议扫描内网主机开放端口 file_get_content 利用file协议查看本地文件: fsockopen() 防御方式: ssrf介绍 服务器端请求伪造,是一种由攻击者构造形成…...
【HarmonyOS】【续集】实现从视频提取音频并保存到pcm文件功能(API6 Java)
【关键字】 视频提取类Extractor、视频编解码、保存pcm文件、getAudioTime 【背景和问题】 上篇中介绍了从视频提取音频并保存到pcm文件功能,请参考文档:https://developer.huawei.com/consumer/cn/forum/topic/0209125665541017202?fid0101591351254…...
MySQL为什么要使用 B+Tree 作为索引结构?
MySQL为什么要使用 BTree 作为索引结构? 基本情况 常规的数据库存储引擎 ,一般都是采用 B 树或者 B树来实现索引的存储。B树是一种多路平衡树,用这种存储结构来存储大量数据,它的整个高度 会相比二叉树来说 ,会矮很多…...
Three.js阴影
目录 Three.js入门 Three.js光源 Three.js阴影 使用灯光后,场景中就会产生阴影。物体的背面确实在黑暗中,这称为核心阴影(core shadow)。我们缺少的是落下的阴影(drop shadow),即对象在其他…...
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,在于它们的可扩展性和灵活性。也就是说,花时间从头开始编码机器学习算法似乎违反直觉,即没有任何基本框架。然而,事实并非…...
Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用
目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限(四表联查)数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…...
SpringWeb项目核心功能总结
SpringWeb项目核心功能总结 文章目录 SpringWeb项目核心功能总结1.浏览器与Java程序的连接(个人偏好使用RequestMapping)2.参数的传入3.结果的返回请求转发和请求重定向的区别 核心功能用到的注解: RestControllerControllerResponseBodyRequ…...
Django------信号
Django 框架包含了一个信号机制,它允许若干个发送者(sender)通知一组接收者(receiver)某些特定操作或事件(events)已经发生了, 接收者收到指令信号(signals)后再去执行特定的操作。本文主要讲解Django信号(…...
HTML5 中新增了哪些表单元素?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTML5 中新增了的表单元素⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚…...
[考研机试] KY20 完数VS盈数 清华大学复试上机题 C++实现
描述 一个数如果恰好等于它的各因子(该数本身除外)子和,如:6321。则称其为“完数”;若因子之和大于该数,则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。 输入描述: 题目没有任何输入。 输出描述&#…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
