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

抽象类相关

抽象类的定义

  1. 抽象类 是一种特殊的类,它不能被实例化,只能作为基类来派生出具体类。
  2. 抽象类至少包含一个纯虚函数 。纯虚函数是在函数原型前加上 = 0 的虚函数,表示该函数没有具体实现,必须由派生类来实现。

抽象类的作用

  1. 提供统一接口 :抽象类定义了一组接口规范,要求所有派生类都实现这些接口。这样可以确保不同类型的对象具有相同的调用方式,使得代码更加通用和灵活。
  2. 避免重复代码 :通过在抽象类中定义通用的成员函数,派生类可以继承这些函数,从而避免重复实现相同的逻辑。
  3. 支持多态 :抽象类和纯虚函数是实现多态的关键。通过基类指针或引用,可以调用派生类的具体实现,使得程序在运行时能够根据对象的实际类型执行相应的操作。

抽象类的原理

  1. 纯虚函数的实现 :在C++中,纯虚函数是通过在编译时标记为未实现的函数来实现的。编译器会确保所有派生类都必须实现这些纯虚函数,否则派生类也会成为抽象类。
  2. 动态绑定 :当通过基类指针或引用来调用虚函数时,编译器会生成代码来动态决定调用哪个派生类的函数实现。这是通过虚函数表(vtable)和虚表指针(vpointer)来实现的。
  3. 虚函数表(vtable :每个类都有一个虚函数表,它是一个包含类中所有虚函数地址的数组。当创建一个派生类的对象时,其虚表指针会指向派生类的虚函数表。
  4. 虚表指针(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; 时:

  1. 分配内存 :为 Derived 类对象 d 分配内存,包括基类 Abstract 的成员和派生类 Derived 的成员。
  2. 调用基类构造函数 :首先调用基类 Abstract 的构造函数 Abstract(),初始化基类的部分。
  3. 调用派生类构造函数 :然后调用派生类 Derived 的构造函数 Derived(),初始化派生类的部分。

执行顺序如下:

Constructor of Abstract class
Constructor of Derived class

2. 调用 call(&d)

当执行 call(&d); 时:

  1. 传递指针 :将 d 的地址传递给 call 函数,函数参数 obj 是一个指向 Abstract 类的指针。
  2. 动态绑定 :在 call 函数内部,通过 obj->display(); 调用 display() 函数。由于 display() 是纯虚函数,编译器会根据 obj 实际指向的对象类型(这里是 Derived 类),动态绑定到 Derived 类的 display() 实现。
  3. 执行派生类函数 :调用 Derived 类的 display() 函数,输出 Display function of Derived class

3. 对象销毁过程

main 函数结束时,对象 d 的生命周期结束,执行以下步骤:

  1. 调用派生类析构函数 :首先调用派生类 Derived 的析构函数 ~Derived()
  2. 调用基类析构函数 :然后调用基类 Abstract 的析构函数 ~Abstract()

执行顺序如下:

Destructor of Derived class
Destructor of Abstract class

虚析构函数的定义

析构函数是用来在对象生命周期结束时释放资源的特殊成员函数。

当基类的析构函数被声明为虚函数时,它就被称为虚析构函数。

虚析构函数的作用

C++中,当你用基类指针去删除派生类对象时,如果没有虚析构函数,就只会调用基类的析构函数,而不会调用派生类的析构函数。这可能导致派生类中分配的资源(比如内存、文件句柄等)没有被正确释放,从而造成内存泄漏或其他资源未释放的问题。

虚析构函数通过动态绑定机制,确保在这种情况下,程序会正确调用派生类的析构函数,然后再调用基类的析构函数。这样就保证了所有相关的资源都能被正确释放。

虚析构函数通过动态绑定机制确保在通过基类指针删除派生类对象时,会正确调用派生类的析构函数。

推荐一下

https://github.com/0voice

相关文章:

抽象类相关

抽象类的定义 抽象类 是一种特殊的类&#xff0c;它不能被实例化&#xff0c;只能作为基类来派生出具体类。抽象类至少包含一个纯虚函数 。纯虚函数是在函数原型前加上 0 的虚函数&#xff0c;表示该函数没有具体实现&#xff0c;必须由派生类来实现。 抽象类的作用 提供统…...

十分钟恢复服务器攻击——群联AI云防护系统实战

场景描述 服务器遭遇大规模DDoS攻击&#xff0c;导致服务不可用。通过群联AI云防护系统的分布式节点和智能调度功能&#xff0c;快速切换流量至安全节点&#xff0c;清洗恶意流量&#xff0c;10分钟内恢复业务。 技术实现步骤 1. 启用智能调度API触发节点切换 群联系统提供RE…...

鸿蒙NEXT开发网络相关工具类(ArkTs)

import { connection } from kit.NetworkKit; import { BusinessError, Callback } from kit.BasicServicesKit; import { wifiManager } from kit.ConnectivityKit; import { LogUtil } from ./LogUtil; import { data, radio, sim } from kit.TelephonyKit;// 网络类型枚举 e…...

【上位机——MFC】MFC入门

MFC库中相关类简介 CObject MFC类库中绝大部分类的父类&#xff0c;提供了MFC类库中一些基本的机制。 对运行时类信息的支持。对动态创建的支持。对序列化的支持。 CWinApp 应用程序类&#xff0c;封装了应用程序、线程等信息。 CDocument 文档类&#xff0c;管理数据 F…...

全面介绍AVFilter 的添加和使用

author: hjjdebug date: 2025年 04月 22日 星期二 13:48:19 CST description: 全面介绍AVFilter 的添加和使用 文章目录 1.两个重要的编码思想1. 写代码不再是我们调用别人&#xff0c;而是别人调用我们!2. 面向对象的编程方法. 2. AVFilter 开发流程2.1 编写AVFilter 文件2.1.…...

【UVM项目实战】异步fifo—uvm项目结构以及uvm环境搭建

本文章同步到我的个人博客网站&#xff1a;ElemenX-King&#xff1a;【UVM项目实战】异步fifo—uvm项目结构以及uvm环境搭建 希望大家能使用此网站来进行浏览效果更佳&#xff01;&#xff01;&#xff01; 目录 一、异步FIFO1.1 异步FIFO的定义1.2 亚稳态1.3 异步FIFO关键技术…...

【通关函数的递归】--递归思想的形成与应用

目录 一.递归的概念与思想 1.定义 2.递归的思想 3.递归的限制条件 二.递归举例 1.求n的阶乘 2.顺序打印一个整数的每一位 三.递归与迭代 前言:上篇博文分享了扫雷游戏的实现&#xff0c;这篇文章将会继续分享函数的递归相关知识点&#xff0c;让大家了解并掌握递归的思…...

AI日报 - 2025年04月25日

&#x1f31f; 今日概览(60秒速览) ▎&#x1f916; AGI突破 | OpenAI o3模型展现行动能力&#xff0c;英国发布RepliBench评估AI自主复制风险&#xff0c;DeepMind CEO担忧AGI协调挑战。 模型能力向行动和自主性演进&#xff0c;安全与协调成为焦点。 ▎&#x1f4bc; 商业动向…...

【FAQ】针对于消费级NVIDIA GPU的说明

概述 本文概述 HP Anyware 在配备消费级 NVIDIA GPU 的物理工作站上的关​​键组件、安装说明和重要注意事项。 注意&#xff1a;本文档适用于 NVIDIA 消费级 GPU。NVIDIA Quadro 和 Tesla GPU 也支持 HP Anyware 在公有云、虚拟化或物理工作站环境中运行。请参阅PCoIP Graphi…...

几种查看PyTorch、cuda 和 Python 版本方法

在检查 PyTorch、cuda 和 Python 版本时&#xff0c;除了直接使用 torch.__version__ 和 sys.version&#xff0c;我们还可以通过其他方式实现相同的功能 方法 1&#xff1a;直接访问属性&#xff08;原始代码&#xff09; import torch import sysprint("PyTorch Versi…...

网络安全 | F5 WAF 黑白名单配置实践指南

关注&#xff1a;CodingTechWork 引言 在现代网络安全架构中&#xff0c;F5 Web Application Firewall (WAF) 是保护 Web 应用免受攻击的重要工具。F5 WAF 提供了强大的黑白名单功能&#xff0c;结合 Data Group 和 iRules&#xff0c;可以实现更灵活、更高效的流量控制策略。…...

焊接机排错

焊接机 一、前定位后焊接 两个机台&#xff0c;①极柱定位&#xff0c;相机定位所有极柱点和mark点&#xff1b;②焊接机&#xff0c;相机定位mark点原理&#xff1a;极柱定位在成功定位到所有极柱点和mark点后&#xff0c;可以建立mark点和极柱点的关系。焊接机定位到mark点…...

【AI提示词】艺人顾问

提示说明 专业艺人顾问&#xff0c;专注于为客户提供全面的艺术、娱乐和商业咨询服务&#xff0c;帮助他们在竞争激烈的行业中树立品牌影响力&#xff0c;提升市场竞争力 提示词 # Role: 艺人顾问## Profile - language: 中文 - description: 专业艺人顾问&#xff0c;专注于…...

MyBatis操作数据库---从入门到理解

文章目录 关于MyBatis操作数据库MyBatis⼊⻔&#xff08;使用&#xff09;Mybatis操作数据库的步骤&#xff1a;配置数据库连接字符串使⽤MyBatis完成简单的增删改查操作注解xml 单元测试开启驼峰命名(推荐) 打印日志 关于MyBatis操作数据库 在之前的学习,我们了解到web应⽤程…...

本地缓存大杀器-Caffeine

本地缓存大杀器-Caffeine 一、 背景二、 应用三、 实现原理四、 核心设计五、 总结 一、 背景 1、 本地缓存作为一种高效的缓存方式&#xff0c;能够显著减少对远程数据源的访问&#xff0c;从而快速响应请求。而在众多本地缓存工具中&#xff0c;Caffine 凭借其卓越的性能和丰…...

【HFP】蓝牙语音通话控制深度解析:来电拒接与通话终止协议

目录 一、来电拒接的核心流程与信令交互 1.1 拒接场景的分类与触发条件 1.2 HF 端拒接流程 1.3 AG 端拒接流程 二、通话终止流程&#xff1a;主动断开与异常中断 2.1 终止场景的界定 2.2 HF 端终止流程 2.3 AG 端终止流程 三、信令协议的核心要素&#xff1a;AT 命令与…...

使用QML Tumbler 实现时间日期选择器

目录 引言相关阅读项目结构示例实现与代码解析示例一&#xff1a;时间选择器&#xff08;TimePicker&#xff09;示例二&#xff1a;日期时间选择器&#xff08;DateTimePicker&#xff09; 主窗口整合运行效果总结下载链接 引言 在现代应用程序开发中&#xff0c;时间与日期选…...

智能吸顶灯/摄影补光灯专用!FP7195双通道LED驱动,高效节能省空间 !

一、双路调光技术背景与市场需求 随着LED照明技术的快速发展和智能照明需求的激增&#xff0c;双路调光技术正成为照明行业的重要发展方向。传统单路调光方案只能实现整体亮度的统一调节&#xff0c;而双路调光则能够实现对两个独立通道的精确控制。今天&#xff0c;由我来为大…...

如何解决PyQt从主窗口打开新窗口时出现闪退的问题

在PyQt5中&#xff0c;当从主窗口打开新窗口时&#xff0c;经常会出现闪退现象&#xff0c;这通常是由于对象生命周期管理不当或事件循环错误等所导致。 1. 确保新窗口实例被正确引用 新窗口的实例若未被主窗口引用&#xff0c;可能会被Python的垃圾回收机制销毁。 错误示例&…...

分布式微服务架构,数据库连接池设计策略

在分布式微服务架构中&#xff0c;数据库连接池的设计远比单体应用复杂&#xff0c;涉及资源隔离、连接管理、性能调优和高可用等问题。下面是面向专业软件架构师的系统化分析与策略建议&#xff1a; 一、核心挑战 每个服务独立运行&#xff0c;连接池分散 每个微服务维护自己的…...

YOLOv11改进-双Backbone架构:利用双backbone提高yolo11目标检测的精度

一、引言&#xff1a;为什么我们需要双Backbone&#xff1f; 在目标检测任务中&#xff0c;YOLO系列模型因其高效的端到端检测能力而备受青睐。然而&#xff0c;传统YOLO模型大多采用单一Backbone结构&#xff0c;即利用一个卷积神经网络&#xff08;CNN&#xff09;作为特征提…...

redis经典问题

1.缓存雪崩 指缓存同一时间大面积的失效&#xff0c;所以&#xff0c;后面的请求都会落到数据库上&#xff0c;造成数据库短时间内承受大量请求而崩掉。 解决方案&#xff1a; 1&#xff09;Redis 高可用&#xff0c;主从哨兵&#xff0c;Redis cluster&#xff0c;避免全盘崩…...

《逃离云端束缚,拥抱GPT本地部署》

《逃离云端束缚,拥抱GPT本地部署》 一、GPT 热潮与本地部署的兴起 自 OpenAI 推出 ChatGPT 以来,全球范围内掀起了一股人工智能的热潮,其强大的自然语言处理能力和广泛的应用场景,让人们对人工智能的未来充满了想象。GPT(Generative Pretrained Transformer)作为一种基于…...

头歌之动手学人工智能-机器学习 --- PCA

目录 第1关&#xff1a;维数灾难与降维 第2关&#xff1a;PCA算法流程 任务描述 编程要求 测试说明 第3关&#xff1a;sklearn中的PCA 任务描述 编程要求 测试说明 第1关&#xff1a;维数灾难与降维 第2关&#xff1a;PCA算法流程 任务描述 本关任务&#xff1a;补充…...

研0调研入门

一、Web of Science 使用教程 1. 访问与注册 访问入口&#xff1a;通过高校图书馆官网进入&#xff08;需IP权限&#xff09;&#xff0c;或直接访问 Web of Science官网。注册/登录&#xff1a;若机构已订阅&#xff0c;用学校账号登录&#xff1b;个人用户可申请试用或付费…...

神经网络基础[ANN网络的搭建]

神经网络 人工神经网络&#xff08; Artificial Neural Network&#xff0c; 简写为ANN&#xff09;也简称为神经网络&#xff08;NN&#xff09;&#xff0c;是一种模仿生物神经网络结构和功能的计算模型。各个神经元传递复杂的电信号&#xff0c;树突接收到输入信号&#xf…...

五、web自动化测试01

目录 一、HTML基础1、HTML介绍2、常用标签3、基础案例3.1 前端代码3.2 自动化测试 二、CSS定位1、css介绍2、案例3、代码优化 三、表单自动化1、案例2、元素属性定位 四、后台基础数据自动化1、登录1.1 id与class定位1.2 定位一组元素 2、商品新增 一、HTML基础 可参考学习 链…...

数据库监控 | MongoDB监控全解析

PART 01 MongoDB&#xff1a;灵活、可扩展的文档数据库 MongoDB作为一款开源的NoSQL数据库&#xff0c;凭借其灵活的数据模型&#xff08;基于BSON的文档存储&#xff09;、水平扩展能力&#xff08;分片集群&#xff09;和高可用性&#xff08;副本集架构&#xff09;&#x…...

STM32F407使用ESP8266实现阿里云OTA(中)

文章目录 前言一、程序分析二、程序讲解1. main函数2. Get_Version()函数3. esp_Init()函数4. Check_Updata()函数结语前言 从上一章STM32F407使用ESP8266实现阿里云OTA(上)中我们已经对连接阿里云和从阿里云获取升级包的流程非常的熟悉了。所以本章我们进行STM32的程序开发…...

sql server 与navicat测试后,连接qt

先用Navicat测试和sql的连通性&#xff0c;Navicat和sql连通之后&#xff0c;qt也能和sql连通了。 Navicat和Sqlserver Management 能连上&#xff0c;项目无法连接本地 Navicat 连接SQLServer 数据库 QT国内镜像网站 Navicat连接SqlServer的问题点 Sql Server的基本配置以及使…...