抽象类相关
抽象类的定义
- 抽象类 是一种特殊的类,它不能被实例化,只能作为基类来派生出具体类。
- 抽象类至少包含一个纯虚函数 。纯虚函数是在函数原型前加上
= 0
的虚函数,表示该函数没有具体实现,必须由派生类来实现。
抽象类的作用
- 提供统一接口 :抽象类定义了一组接口规范,要求所有派生类都实现这些接口。这样可以确保不同类型的对象具有相同的调用方式,使得代码更加通用和灵活。
- 避免重复代码 :通过在抽象类中定义通用的成员函数,派生类可以继承这些函数,从而避免重复实现相同的逻辑。
- 支持多态 :抽象类和纯虚函数是实现多态的关键。通过基类指针或引用,可以调用派生类的具体实现,使得程序在运行时能够根据对象的实际类型执行相应的操作。
抽象类的原理
- 纯虚函数的实现 :在
C++
中,纯虚函数是通过在编译时标记为未实现的函数来实现的。编译器会确保所有派生类都必须实现这些纯虚函数,否则派生类也会成为抽象类。 - 动态绑定 :当通过基类指针或引用来调用虚函数时,编译器会生成代码来动态决定调用哪个派生类的函数实现。这是通过虚函数表(
vtable
)和虚表指针(vpointer
)来实现的。 - 虚函数表(
vtable
) :每个类都有一个虚函数表,它是一个包含类中所有虚函数地址的数组。当创建一个派生类的对象时,其虚表指针会指向派生类的虚函数表。 - 虚表指针(
vpointer
) :每个包含虚函数的类的对象都有一个隐藏的指针,称为虚表指针,它指向该类的虚函数表。当通过基类指针调用虚函数时,编译器会通过虚表指针查找并调用相应的函数实现。
示例代码
#include <iostream>
using namespace std;class Abstract
{
public:virtual void display() = 0; // pure virtual functionAbstract(){cout << "Constructor of Abstract class" << endl;}virtual ~Abstract(){cout << "Destructor of Abstract class" << endl;}
};class Derived : public Abstract
{
public:void display(){cout << "Display function of Derived class" << endl;}Derived(){ cout << "Constructor of Derived class" << endl;}~Derived(){cout << "Destructor of Derived class" << endl;}
};void call(Abstract *obj)
{obj->display();
}int main()
{Derived d;call(&d);return 0;
}
为什么构造函数不能被声明为虚函数?
构造函数是给对象分配内存和初始化成员变量的,编译器要提前知道调用哪个构造函数,才能准确地分配内存和初始化。
就好比造汽车,必须先确定用哪个模具(构造函数),才能准备好材料和工具(分配内存)并开始组装(初始化成员变量)。
构造函数不是用来实现运行时多态的,它是为了确保对象在创建时就处于一个有效的初始状态。虚函数机制用于支持运行时多态,是通过虚函数表(vtable
)和虚表指针(vpointer
)实现的。
在C++
中,创建派生类对象时,基类构造函数先执行,接着才是派生类构造函数。假若构造函数被设为虚函数,那在基类构造函数运行时,派生类构造函数还没执行,对象的动态类型尚未确定,编译器就无法知晓该调用哪个构造函数。
另外,虚函数表的初始化是在对象构造过程中完成的。在构造函数执行前,虚函数表指针(vpointer
)尚未初始化。若构造函数是虚函数,调用时虚函数表指针未设置好,就无法确定具体调用哪个构造函数。所以,构造函数不能是虚函数。
正是因为构造函数的调用必须在编译时确定,而虚函数机制依赖于运行时的动态绑定,所以构造函数不能是虚函数。这样的设计确保了对象能够正确初始化,并且构造过程是可预测的。
虚函数表(vtable
)的初始化主要发生在哪些阶段?
1. 编译阶段,为每个包含虚函数的类生成虚函数表
虚函数表是一个包含该类所有虚函数地址的数组。
编译器会根据类的定义和继承关系来构建这个表。
对于派生类,其虚函数表会包含基类的虚函数和派生类自己的虚函数,如果派生类重写了基类的虚函数,则虚函数表中将使用派生类的实现覆盖基类的实现。
2. 对象构造阶段,为每个创建的对象分配虚表指针(vpointer
)
虚表指针(vpointer
)指向该对象对应的虚函数表。
这个指针的初始化发生在对象的构造函数执行之前。
具体来说,基类构造函数首先执行,在基类构造函数中,对象的虚表指针被初始化为基类的虚函数表。当派生类构造函数执行时,虚表指针会被更新为派生类的虚函数表。
3. 动态绑定阶段,通过虚表指针查找对应函数
在对象的生命周期中,虚表指针始终指向该对象对应的虚函数表。
当调用虚函数时,编译器会通过虚表指针查找并调用相应的函数。
如果对象的类型在运行时发生变化(例如,通过多态),虚表指针会指向不同的虚函数表,从而实现动态绑定。
4. 总结
虚函数表的初始化主要在编译阶段和对象构造阶段完成。
编译器在编译时为每个类生成虚函数表,在对象构造时为对象的虚表指针赋值。
虚函数表的初始化确保了在调用虚函数时能够正确地找到对应的函数实现,支持运行时的多态行为。
纯虚函数和虚函数的区别
纯虚函数 :在函数声明后面加上 = 0
,表示该函数没有具体实现,必须由派生类来实现。包含纯虚函数的类是抽象类,不能被实例化。
虚函数 :普通的虚函数有具体实现,可以在基类中定义,派生类可以重写也可以不重写。如果派生类不重写,将继承基类的实现。
两者都用于实现运行时多态性,但纯虚函数强制派生类必须提供实现,而虚函数允许派生类选择是否重写。
包含纯虚函数的类是抽象类,不能实例化;而包含虚函数的类可以是具体类,可以实例化。
调用 call(&d)
时,对象的创建和销毁过程
1. 对象创建过程
当执行 Derived d;
时:
- 分配内存 :为
Derived
类对象d
分配内存,包括基类Abstract
的成员和派生类Derived
的成员。 - 调用基类构造函数 :首先调用基类
Abstract
的构造函数Abstract()
,初始化基类的部分。 - 调用派生类构造函数 :然后调用派生类
Derived
的构造函数Derived()
,初始化派生类的部分。
执行顺序如下:
Constructor of Abstract class
Constructor of Derived class
2. 调用 call(&d)
当执行 call(&d);
时:
- 传递指针 :将
d
的地址传递给call
函数,函数参数obj
是一个指向Abstract
类的指针。 - 动态绑定 :在
call
函数内部,通过obj->display();
调用display()
函数。由于display()
是纯虚函数,编译器会根据obj
实际指向的对象类型(这里是Derived
类),动态绑定到Derived
类的display()
实现。 - 执行派生类函数 :调用
Derived
类的display()
函数,输出Display function of Derived class
。
3. 对象销毁过程
当 main
函数结束时,对象 d
的生命周期结束,执行以下步骤:
- 调用派生类析构函数 :首先调用派生类
Derived
的析构函数~Derived()
。 - 调用基类析构函数 :然后调用基类
Abstract
的析构函数~Abstract()
。
执行顺序如下:
Destructor of Derived class
Destructor of Abstract class
虚析构函数的定义
析构函数是用来在对象生命周期结束时释放资源的特殊成员函数。
当基类的析构函数被声明为虚函数时,它就被称为虚析构函数。
虚析构函数的作用
在C++
中,当你用基类指针去删除派生类对象时,如果没有虚析构函数,就只会调用基类的析构函数,而不会调用派生类的析构函数。这可能导致派生类中分配的资源(比如内存、文件句柄等)没有被正确释放,从而造成内存泄漏或其他资源未释放的问题。
虚析构函数通过动态绑定机制,确保在这种情况下,程序会正确调用派生类的析构函数,然后再调用基类的析构函数。这样就保证了所有相关的资源都能被正确释放。
虚析构函数通过动态绑定机制确保在通过基类指针删除派生类对象时,会正确调用派生类的析构函数。
推荐一下
https://github.com/0voice
相关文章:
抽象类相关
抽象类的定义 抽象类 是一种特殊的类,它不能被实例化,只能作为基类来派生出具体类。抽象类至少包含一个纯虚函数 。纯虚函数是在函数原型前加上 0 的虚函数,表示该函数没有具体实现,必须由派生类来实现。 抽象类的作用 提供统…...
如何测试短信接口
目录 一、测试短信接口的基本流程 1. 了解短信接口文档 2. 使用工具测试短信接口 示例一:用 curl 测试 POST 请求 示例二:用 Postman 设置 POST 请求 3. 编写测试脚本(Python 示例) 二、测试类型和场景 ✅ 正常发送测试 …...
pycharm2024.3.2项目解释器选择问题
问题描述:已经选择了pyau虚拟环境的解释器,运行了conda activate pyau,但是为什么关闭pycharm2024.3.2软件重新启动后,打开终端是(base) PS D:\deepseektest> ,为什么不是(pyau) PS D:\deepseektest> 解决问题&a…...
如何在 Dialog 中安全初始化 ECharts 并自动监听容器大小变化
如何在 Dialog 中安全初始化 ECharts 并自动监听容器大小变化 在使用 ECharts 的 Vue 项目中,我们常常会将图表放入弹窗(如 Element UI 的 <el-dialog>)中进行展示。但你是否遇到过以下问题: 图表初次显示尺寸异常&#x…...
如何借助ETL数据集成工具实现数据一致性?
主要可以从以下几个方面入手: 一、数据抽取阶段(Extract) 统一数据源连接方式:ETL工具通常支持多种数据源连接方式,如关系型数据库、非关系型数据库、文件系统、API接口等。在抽取数据时,要确保对各个数据…...
3.4/Q1,GBD数据库最新文章解读
文章题目:Burden of Carbon Monoxide Poisoning in Asian Countries From 1990 to 2021 and Its Projection Until 2030: An Analysis of the Global Burden of Disease Study 2021 DOI:10.2147/CLEP.S512786 中文标题:1990 年至 2021 年亚洲…...
【高中数学/古典概率】4红2黑六选二,求取出两次都是红球的概率
【问题】 袋子里装4只红球,2只黑球,大小完全相同,抽两次球,每次抽一只,抽出后不再放回,求取出的两次都是红球的概率。 【来源】 数林外传系列之《概率与期望》P20 单埻著 中国科学技术大学出版社 【数学…...
机器人操作中的生成式 AI:综述(上)
25年3月来自香港大学、香港理工、香港科大、浙大和清华大学的论文“Generative Artificial Intelligence in Robotic Manipulation: A Survey”。 本综述全面回顾机器人操作领域生成学习模型的最新进展,并探讨该领域的关键挑战。机器人操作面临着关键瓶颈ÿ…...
Spring AI 核心概念
本文是对Spring AI中涉及到的AI相关核心概念的介绍,笔者结合LangChain、LlamaIndex的使用经验,尝试尽可能清晰的把这些概念解释清楚. 读者也可以参考官方文档作为补充. 模型 提到AI模型,我们的第一印象一定是GPT,DeepSeek这样的大语言模型(…...
第53.5讲 | 小项目实战:用 SHAP 值解释农作物产量预测模型 [特殊字符][特殊字符]
目录 ✅ 项目背景 📦 所用工具 📁 数据字段(模拟) 🧑💻 代码实现步骤 🎯 解读与启发 🧠 项目拓展建议 ✅ 项目背景 我们使用一个简化的玉米产量数据集(可模拟实…...
Linux编译器-gcc/g++使用
1.预处理(进行宏替换) -E开始进行程序编译,在预处理做完的时候,停下来 2.编译(生成汇编) -S 开始编译,编译做完了就停下来 3.汇编(生成机器可识别代码) -c 开始翻译汇编…...
SEO的关键词研究与优化 第二章
回顾上一篇文章, 3. 关键词评估和选择 关键词评估和选择是SEO策略中至关重要的一步。这个过程不仅仅是选择搜索量最高的词,而是要在多个因素之间找到平衡,以确定最有价值的关键词。 3.1 搜索量分析 搜索量是评估关键词潜力的首要指标,但它不应…...
数据结构数组
数组特点 内存是连续的,所以地址可以偏移,支持下标访问。 优点 下标访问(随机访问)的时间复杂度是O(1),末尾增加和删除元素的时间复杂度是O(1)。 访问元素前后相邻位置方便,因为数组每个位置内存是连续的ÿ…...
vscode插件系列-2、认识vscode
这一章,我将带你重新认识vscode 一、工作区划分 1、活动条(Activity Bar) 活动条是一个核心的导航,扩展可以通过在View Containers中配置,从而渲染Views中的视图。 具体来说就是在package.json中配置如下&…...
Java学习手册:TCP 协议基础
一、TCP 协议概述 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,它在 IP 协议的基础上提供了可靠的 数据传输服务。TCP 通过三次握手建立连接,通过四次挥手…...
摘要 | 李录在北大光华管理学院的演讲《价值投资》
李录在北大光华管理学院的演讲《价值投资》是中文投资领域极具影响力的经典内容,尤其是2019年11月的演讲版本。该演讲视频时长90分钟,主要内容围绕价值投资的理论框架、实践难点以及在中国市场的应用展开。以下是该演讲的核心要点解析: 一、价…...
让Docker端口映射受Firewall管理而非iptables
要让Docker容器的端口映射受系统防火墙(如firewalld或ufw)管理,而不是直接通过iptables,可以按照以下步骤配置: 方法一:禁用Docker的iptables规则 (1)编辑Docker配置文件: vi /etc/docker/da…...
数据库数据删除与修改实验
数据库数据删除与修改实验 在数据库原理的学习中,数据的删除与修改是核心操作技能。通过“删除修改数据”实验,我系统实践了 SQL 中 UPDATE 和 DELETE 语句的多种应用场景,从基础语法到复杂业务逻辑处理,积累了丰富的实战经验。本…...
多回路电表如何革新电力监控?安科瑞技术深度解析
安科瑞顾强 安科瑞电气股份有限公司作为国内领先的能源管理方案提供商,其多回路智能电表系列(如AMC200、AMC300L、ADW200-D10-4S等)凭借多回路计量、高精度测量、无线物联等核心优势,在工业、商业及智能电网领域广泛应用。以下从…...
【云计算】云计算中IaaS、PaaS、SaaS介绍
0 随着云计算、大数据、人工智能发展迅速,布局“云”已经是互联网企业共识。云计算的服务类型分为三种,分别为IaaS、PaaS、SaaS,这三个分别是什么意思,今天做一个简单的介绍和了解。 一、云计算 云计算是用户需求通过Internet获…...
Ubuntu中选择Python虚拟环境
背景 在Ubuntu系统中,如果希望通过一个简单的命令(例如activate)快速查找并激活Python虚拟环境,是可以通过Bash脚本实现的。该脚本的核心功能包括:递归扫描用户家目录(~)中所有非隐藏文件夹&am…...
Nginx 安装与配置全流程指南(2025 最新版)
一、环境准备与依赖安装 1.1 系统要求 操作系统:支持主流 Linux 发行版(Ubuntu 20.04/CentOS 7/Debian 10)硬件配置:内存 ≥512MB,磁盘 ≥10GB 可用空间(建议使用 SSD)网络要求:开…...
WAMP设置外网访问
系统:windows 软件:wampserver 设置允许外网访问 1.修改apache的httpd-vhosts.config # Virtual Hosts # <VirtualHost _default_:80>ServerName localhostServerAlias localhostDocumentRoot "${INSTALL_DIR}/www"<Directory "…...
NXP----SVR5510芯片layout设计总结
1,Pinout Information: VR5510是S32G应用处理器的拟议电源管理集成电路(PMIC)。它是一款汽车多输出PMIC,主要用于网关、ADAS、V2X和信息娱乐应用。下面的方框图展示了其主要特点。 2,封装设计&…...
面试之消息队列
消息队列场景 什么是消息队列? 消息队列是一个使用队列来通信的组件,它的本质就是个转发器,包含发消息、存消息、消费消息。 消息队列怎么选型? 特性ActiveMQRabbitMQRocketMQKafka单机吞吐量万级万级10万级10万级时效性毫秒级…...
[创业之路-386]:企业法务 - 知识产权的刑事风险
知识产权的刑事风险是指因侵犯他人知识产权而可能面临的刑事法律责任。 对于初创公司而言,了解并防范此类风险至关重要,以下从不同知识产权类型展开详细分析: 一、侵犯商标权的刑事风险 风险表现:未经注册商标所有人许可&#…...
Freertos----中断管理
一、中断概念 在RTOS中,需要应对各类事件。这些事件很多时候是通过硬件中断产生,怎么处理中断呢? 假设当前系统正在运行Task1时,用户按下了按键,触发了按键中断。这个中断的处理流程如下: CPU跳到固定地…...
4.4 记忆机制与上下文管理:短期与长期记忆的设计与应用
记忆机制与上下文管理已成为智能代理(Agent)系统实现高效、智能化行为的核心技术。记忆机制通过短期记忆(Short-Term Memory, STM)和长期记忆(Long-Term Memory, LTM)支持Agent存储、检索和利用信息&#x…...
ERROR: x264 not found using pkg-config
x264 编译加上了参数,–prefix/usr/local/x264/,找不到x264.pc ffmpeg安装过程中configure报错: sudo ./configure --enable-gpl --enable-libx264 --enable-shared --extra-ldflags-L/usr/lib --extra-cflags-I/usr/include --pkg-config“…...
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
统一HTTP请求代码 public class HttpCode {/*** 操作成功*/public static final int SUCCESS 200;/*** 对象创建成功*/public static final int CREATED 201;/*** 请求已经被接受*/public static final int ACCEPTED 202;/*** 操作已经执行成功,但是没有返回数据…...
架构-系统可靠性分析与设计
一、可靠性相关基本概念 1. 可靠性与可用性 可靠性:软件系统在遇到错误、意外操作或系统故障时,仍能维持自身功能特性的能力。 举例:手机银行APP在用户误操作(如快速点击多次转账)时,仍能正确处理交易并避…...
Tailwind CSS 初学者入门指南:项目集成,主要变更内容!
网站名称类型网址Tailwind CSS 官方文档官方文档https://tailwindcss.com/docsTailwind Play在线编辑器https://play.tailwindcss.com/Tailwind Awesome资源集合https://www.tailwindawesome.com/Tailwind CSS 中文文档中文文档https://www.tailwindcss.cn/komavideo/LearnTail…...
HOJ.单词统计
目录 题目算法标签: 模拟, 字符串操作思路代码*后续 A C AC AC代码 题目 一段英语短文的内容记录于 lines 中,每行输入 lines[i] 仅包含 a-z , . , -,即英文小写字母,空格,逗号,句号和续行符。 请统计单词数量&#…...
C++ round 函数笔记 (适用于算法竞赛)
在算法竞赛中,处理浮点数并将其转换为整数是常见的需求,round 函数是标准库提供的用于执行“四舍五入”到最近整数的工具。理解其工作方式和潜在问题对于避免错误至关重要。 1. 基本用法 头文件 要使用 round 函数,需要包含 <cmath>…...
远程访问服务器的Jupyter Notebook
在 Linux 服务器上安装 Jupyter Notebook 可以直接调用服务器资源,适合处理大规模数据处理、复杂模型训练等计算密集型任务,避免本地设备算力不足的限制。 一、安装 Jupyter Notebook(在服务器上) 激活 conda 环境安装 conda install jupyter notebook 关于安装命名 1.…...
DNS实验
DNS原理 客户端发起请求:客户端向本地 DNS 服务器发送域名解析请求,这是流程的起始点。本地 DNS 服务器查询根域名服务器:若本地 DNS 服务器缓存中无对应记录,它向根域名服务器发起查询,根域名服务器是 DNS 系统顶层&a…...
SQL实战:02之连续数问题求解
文章目录 概述题目:体育馆的人流量题解步骤一:构造出一个连续序列步骤二:找出符合条件的组的序号步骤三:fetch结果,使用内连接过滤出符合条件的记录。完整SQL 题目二:连续出现的数字题解步骤一:分区并构建连…...
【C++】STL之deque
deque Deque 的底层既不直接依赖 vector 也不依赖 list,而是结合了两者的思想,采用了一种分块(chunk)存储与动态指针数组(map)结合的结构。以下是详细分析: 1. 底层结构设计 Deque 的核心设计…...
HTB - BigBang靶机记录
HTB - BigBanghttps://mp.weixin.qq.com/s/D7yR00kHdiIfoOFk_jHa9w...
AI时代的能力重构与终身进化
在数字技术加速迭代、职业边界日益模糊的当下,自我提升已从“阶段式学习”演变为“持续性进化”。这一转型的底层逻辑在于:个体能力需从“知识积累”转向“能力重构”,以适应AI技术重塑的社会分工与价值创造模式。本文将从认知升级、技能进化、生态构建三个维度,解析AI时代…...
Java—— 正则表达式 方法及捕获分组
识别正则表达式的方法 方法名说明public String[] matches(String regex) 判断字符串是否满足 正则表达式的规则 public string replaceAll(String regex,string newstr) 按照正则表达式的 规则进行替换 public string[] split(String regex) 按照正则表达式的 规则切割字符串…...
《100天精通Python——基础篇 2025 第2天:Python解释器安装与基础语法入门》
目录 一、Windows安装Python1.1 下载并安装 Python1.2 测试安装是否成功 二、Linux系统安装Python(新手可以跳过)2.1 基于RockyLinux系统安装Python(编译安装)2.2 基于Ubuntu系统安装Python(编译安装)2.3 macOS 安装python解释器 三、如何运行Python程序?3.1 Python…...
Linux平台实现低延迟的RTSP、RTMP播放
在流媒体播放器的开发过程中,RTSP(实时流协议)和RTMP(实时消息协议)是广泛应用的流媒体协议。本博客将介绍如何使用大牛直播SDK实现一个Linux平台下的RTSP/RTMP播放器。大牛直播SDK的Linux平台播放SDK,支持…...
安宝特案例 | AR技术在院外心脏骤停急救中的革命性应用
00 案例背景 在院外心脏骤停 (OHCA) 的突发救援中,时间与效率直接决定着患者的生命。传统急救模式下,急救人员常通过视频或电话与医院医生进行沟通,以描述患者状况并依照指令行动。然而,这种信息传递方式往往因信息不完整或传递延…...
chili3d调试笔记9 参数化建模+ai生成立方体
mainwindow 怎么渲染boxnode https://github.com/ticket180/chili3d chili3d ai画立方体...
天梯——L1-110 这不是字符串题
代码 #include<bits/stdc.h> using namespace std; int main(){int n,m;cin>>n>>m;string s;for(int i0;i<n;i){int x;cin>>x;schar(x0);}while(m--){int x;cin>>x;if(x1){int l1;string s1;cin>>l1;for(int i0;i<l1;i){int a;cin&…...
React在什么情况下需要用useReducer
在 React 中,useReducer 是一个用于管理复杂状态逻辑的 Hook。它是 useState 的替代方案,适用于状态更新逻辑复杂或状态之间相互关联的场景。 什么时候需要使用 useReducer 状态更新逻辑复杂: 如果状态更新涉及多个操作或有复杂的逻辑&#x…...
要从给定的数据结构中提取所有的 itemList 并将其放入一个新的数组中
const data [{id:1,itemList:[{id:1-1,list:0},{id:1-2,list:0}]},{id:2,itemList:[{id:2-1,list:0}]} ]使用 forEach const newItemList [];data.forEach(item > {newItemList.push(...item.itemList); });console.log(newItemList);reduce const newItemList data.re…...
程序员鱼皮最新项目-----AI超级智能体教程(一)
文章目录 1.前言1.什么是AI大模型2.什么是多模态3.阿里云百炼平台介绍3.1文本调试展示3.2阿里云和dashscope的关系3.3平台智能体应用3.4工作流的创建3.5智能体编排应用 1.前言 最近鱼皮大佬出了一套关于这个AI 的教程,关注鱼皮大佬很久了,鱼皮大佬确实在…...
17.磁珠在EMC设计中的运用
磁珠在EMC设计中的运用 1. 磁珠的高频等效特性2. 磁珠的参数分析与选型3. 磁珠应用中的隐患问题 1. 磁珠的高频等效特性 和磁环类似,低频段感性jwL为主,高频段阻性R为主。 2. 磁珠的参数分析与选型 不需要太在意磁珠在100MHz时的电阻值,选型…...