虚函数、纯虚函数、多态
一.虚函数
在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据所指对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数。
(一)虚表和虚基表指针
虚函数表(Virtual Function Table)
- 在C++中,每个类(包括基类和派生类)包含一个虚函数表,也称为虚表(vtable)。虚表是一个包含虚函数指针的数组,每个虚函数指针指向相应虚函数的地址。虚表是在编译时创建的,并且对于每个类只有一个。
- 虚表是类的元数据,它记录了该类的虚函数及其位置。当类的对象被创建时,一个指向虚表的指针会添加到对象的内存布局中。
虚表指针
- 在含有虚函数的类实例化对象时,对象地址的前四个字节存储的指向虚表的指针,它是在构造函数中被初始化的。

(二)纯虚函数
纯虚函数(Pure Virtual Function)是C++中的一个特殊类型的虚拟函数,它在基类中声明但没有定义。纯虚函数的声明使用virtual关键字,并在函数声明的末尾添加= 0来表示它是一个纯虚函数。子类(派生类)必须提供纯虚函数的实际实现,否则子类也会被标记为抽象类,无法创建对象。
class Shape {
public:// 声明纯虚函数virtual void draw() = 0;// 普通成员函数void displayInfo() {// 这里可以包含一些通用的代码std::cout << "This is a shape." << std::endl;}
};class Circle : public Shape {
public:// 子类必须提供纯虚函数的实现void draw() override {std::cout << "Drawing a circle." << std::endl;}
};class Square : public Shape {
public:// 子类必须提供纯虚函数的实现void draw() override {std::cout << "Drawing a square." << std::endl;}
};int main() {Circle circle;Square square;circle.displayInfo(); // 调用基类函数circle.draw(); // 调用派生类函数square.displayInfo(); // 调用基类函数square.draw(); // 调用派生类函数return 0;
}
在上述示例中,Shape类包含一个纯虚函数draw(),因此Shape类本身是一个抽象类,不能创建它的对象。然后,Circle和Square类都继承自Shape类,并必须提供对draw()的实际实现。这种机制允许多态性(Polymorphism)的实现,允许不同的派生类以不同的方式实现相同的虚拟函数。
二.多态的实现
根据上图举例分析:
#include<iostream>
#include<vector>
using namespace std;
class A {
public:virtual void prints() {cout << "A::prints" << endl;}A() {cout << "A:构造函数" << endl;}
};
class B:public A {
public:virtual void prints() {cout << "B::prints" << endl;}B() {cout << "B:构造函数" << endl;}
};
class C :public A {
public:};
int main() {A *b = new B();b->prints();b = new C();b->prints();return 0;
}

多态的原理:
1.虚函数表和虚指针(上面)
2.虚函数声明和覆盖:
-
在基类中声明虚函数时,使用
virtual关键字。这告诉编译器将该函数视为虚函数,它可以在派生类中被覆盖(重写)。 -
派生类中的虚函数覆盖基类中的虚函数时,必须使用
override关键字,以确保正确的函数被覆盖。这也使得代码更容易阅读和维护
3.动态绑定的过程:
-
当您使用基类指针或引用调用虚函数时,编译器不会在编译时决定要调用哪个函数版本。相反,它会在运行时根据对象的实际类型来选择正确的函数版本。
-
这个过程大致如下:
- 在基类指针或引用上调用虚函数。
- 运行时系统会查找对象的虚表指针。
- 使用虚表指针找到虚表。
- 从虚表中获取正确的函数指针。
- 调用相应的函数。
4.多态性的优势:
- 多态性无需关心对象的具体类型,从而提高了代码的可复用性和可维护性。
- 它允许轻松扩展代码,通过添加新的派生类来增加功能,而不必修改现有的代码。
- 多态性还支持抽象编程,允许定义基于接口的类,然后通过派生类来实现具体的功能。
总结一下,多态的原理基于虚函数和虚表,它允许在运行时根据对象的实际类型来选择要调用的函数版本,从而实现了面向对象编程中的灵活性和可扩展性。多态性是C++和其他面向对象编程语言的核心概念之一,有助于构建可维护和可扩展的软件系统。
三.为什么析构函数一般写成虚函数?
由于类的多态性,通常通过父类指针或引用来操作子类对象。因为多套允许我们以统一的方式处理不同的派生类对象,并且在运行时确定要调用的方法。
如果析构函数不被声明为虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样会造成派生类析构不完全,造成内存泄漏。
这种行为是为了确保资源的正确释放。由于我们只知道父类的类型,编译器无法确定指针指向的是哪个子类对象,因此只能调用父类的析构函数来释放资源。
没有虚析构:
#include<iostream>
#include<vector>
using namespace std;
class A {
public:virtual void prints() {cout << "A::prints" << endl;}A() {cout << "A:构造函数" << endl;}virtual ~A() {cout << "A:析构函数 " << endl;}
};
class B:public A {
public:virtual void prints() {cout << "B::prints" << endl;}B() {cout << "B:构造函数" << endl;}~B() {cout << "B:析构函数 " << endl;}
};
int main() {A *b = new B();b->prints();delete b;b = NULL;return 0;
}

虚析构:
#include<iostream>
#include<vector>
using namespace std;
class A {
public:virtual void prints() {cout << "A::prints" << endl;}A() {cout << "A:构造函数" << endl;}virtual ~A() {cout << "A:析构函数 " << endl;}
};
class B:public A {
public:virtual void prints() {cout << "B::prints" << endl;}B() {cout << "B:构造函数" << endl;}~B() {cout << "B:析构函数 " << endl;}
};
int main() {A *b = new B();b->prints();delete b;b = NULL;return 0;
}

分析:可以看到析构函数是,先从子类析构,再到父类析构
相关文章:
虚函数、纯虚函数、多态
一.虚函数 在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据所指对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数。 …...
QGIS学习3 - 安装与管理插件
QGIS安装与管理插件主要是使用了菜单栏安装与管理插件这个菜单。 1、通过压缩文件等添加非官方插件 通过压缩文件添加有可能会提示存在安全问题等,直接点是即可。 之后点击install plugins即可完成。安装后导入插件 但是load失败了应该是安装没有成功。只能通过u…...
LeetCode377. 组合总和 Ⅳ
377. 组合总和 Ⅳ 文章目录 [377. 组合总和 Ⅳ](https://leetcode.cn/problems/combination-sum-iv/)一、题目二、题解方法一:完全背包一维数组动态规划思路代码分析 方法二:动态规划二维数组 一、题目 给你一个由 不同 整数组成的数组 nums ࿰…...
QT将数据写入文件,日志记录
项目场景: 在QT应用中,有时候需要将错误信息记录在log文件里面,或者需要将数据输出到文件中进行比对查看使用。 创建log文件,如果文件存在则不创建 QDir dir(QCoreApplication::applicationDirPath()"/recv_data");if(…...
vue2与vue3的使用区别与组件通信
1. 脚手架创建项目的区别: vue2: vue init webpack “项目名称”vue3: vue create “项目名称” 或者vue3一般与vite结合使用: npm create vitelatest yarn create vite2. template中结构 vue2: template下只有一个元素节点 <template><div><div…...
亚信科技与中国信通院达成全方位、跨领域战略合作
9月11日,亚信科技(中国)有限公司「简称:亚信科技」与中国信息通信研究院「简称:中国信通院」在京达成战略合作,双方将在关键技术研发、产业链协同等方面展开全方位、跨领域、跨行业深度合作,共促…...
华为Linux系统开发工程师面试
在Linux系统开发工程师的面试中,你可能会遇到以下一些问题: 在同一个网站中,当客户访问的时候,会出现有的页面访问的速度快而有的慢,系统和服务完全正常、网络带宽正常,你如何诊断这个问题?你以…...
Qt利用QTime实现sleep效果分时调用串口下发报文解决串口下发给下位机后产生的粘包问题
Qt利用QTime实现sleep效果分时调用串口下发报文解决串口下发给下位机后产生的粘包问题 文章目录 Qt利用QTime实现sleep效果分时调用串口下发报文解决串口下发给下位机后产生的粘包问题现象解决方法 现象 当有多包数据需要连续下发给下位机时,比如下载数据等&#x…...
人工智能:神经细胞模型到神经网络模型
人工智能领域中的重要流派之一是:从神经细胞模型(Neural Cell Model)到神经网络模型(Neural Network Model)。 一、神经细胞模型 第一个人工神经细胞模型是“MP”模型,它是由麦卡洛克、匹茨合作࿰…...
Redisson分布式锁实战
实战来源 此问题基于电商 这周遇见这么一个问题,简略的说一下 由MQ发布了两个消息,一个是订单新增,一个是订单状态变更 由于直接付款之后,这两个消息的发布时间不分先后,可能会造成两种情况,1、订单状态变更…...
JavaScript中循环遍历数组、跳出循环和继续循环
循环遍历数组 上个文章我们简单的介绍for循环,接下来,我们使用for循环去读取数据的数据,之前我们写过这样的一个数组,如下: const ITshareArray ["张三","二愣子","2033-1997","…...
Java——》Synchronized和Lock区别
推荐链接: 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…...
JDK20 + SpringBoot 3.1.0 + JdbcTemplate 使用
JDK20 SpringBoot 3.1.0 JdbcTemplate 使用 一.测试数据库 Postgres二.SpringBoot项目1.Pom 依赖2.配置文件3.启动类4.数据源配置类5.实体对象类包装类6.测试用实体对象1.基类2.扩展类 7.测试类 通过 JdbcTemplate 直接执行 SQL 语句,结合源码动态编译即可方便实现…...
CTFhub_SSRF靶场教程
CTFhub SSRF 题目 1. Bypass 1.1 URL Bypass 请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧 1.利用?绕过限制urlhttps://www.baidu.com?www.xxxx.me 2.利用绕过限制urlhttps://www.baidu.comwww.xxxx.me 3.利用斜…...
【华为OD机试】单词接龙【2023 B卷|100分】
【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述: 单词接龙的规则是:可用于接龙的单词首字母必须要前一个单词的尾字母相同; 当存在多个首字母相同的单词时,取长度最长的单词,如果长度也相等, 则取字典序最小的单词;已经参与接龙…...
如何优雅的实现无侵入性参数校验之spring-boot-starter-validation
在开发过程中,参数校验是一个非常重要的环节。但是,传统的参数校验方法往往需要在代码中手动添加大量的 if-else 语句,这不仅繁琐,而且容易出错。为了解决这个问题,我们可以使用无侵入性参数校验的方式来简化代码并提高…...
企业架构LNMP学习笔记27
Keepalived的配置补充: 脑裂(裂脑):vip出现在了多台机器上。网络不通畅,禁用了数据包,主备服务器没法通讯,造成备服务器认为主服务器不可用,绑定VIP,主服务器VIP不会释放…...
品牌策划经理工作内容|工作职责|品牌策划经理做什么?
一位美国作家曾说过“品牌是一系列期望、记忆、故事和关系,他们共同构成了消费者最终原则一个产品或者服务的原因。” 所以,品牌经理这个岗位主要是创造感知价值主张,激发消费者购买这个品牌后带来的感知价值,这种回报的本质相对…...
【设计模式】三、概述分类+单例模式
文章目录 概述设计模式类型 单例模式饿汉式(静态常量)饿汉式(静态代码块)懒汉式(线程不安全)懒汉式(线程安全,同步方法)懒汉式(线程安全,同步代码块)双重检查静态内部类枚举单例模式在 JDK 应用的源码分析 …...
手把手教学 Springboot+ftp+下载图片
简单教学,复制即用的Ftp下载图片 引入配置包 <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency><dependency><grou…...
在Windows上优雅运行Android应用:APK Installer的零门槛解决方案
在Windows上优雅运行Android应用:APK Installer的零门槛解决方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾为无法在Windows电脑上使用某个心…...
【51单片机一个按键切合初始流水灯按一下对半闪烁按一下显示时间】2023-10-16
缘由51单片机按键切换流水灯和时钟_嵌入式-CSDN问答 我想搞一个按键切换在初始状态流水灯按一下到双闪灯再按一下到时钟,可是之中如果用延时函数会导致CPU不能运行很多事情造成卡顿,利用中断的话定时检测的时间又不一样,我试着编译了代码但发…...
从零部署OpenClaw:打造私有AI助手全流程指南
1. 项目概述:从零部署你的专属AI助手 如果你对AI Agent(智能体)感兴趣,想拥有一个能24小时在线、不仅能聊天还能帮你执行任务、操控浏览器、生成图片的私人助手,但又觉得技术门槛太高、无从下手,那么你来对…...
VMware macOS虚拟机深度解锁指南:Unlocker 3.0架构剖析与实战应用
VMware macOS虚拟机深度解锁指南:Unlocker 3.0架构剖析与实战应用 【免费下载链接】unlocker VMware Workstation macOS 项目地址: https://gitcode.com/gh_mirrors/unloc/unlocker 在虚拟化技术领域,VMware Workstation和Player用户长期面临一个…...
工业现场故障排查:从温度敏感故障到CMOS浮空输入根因分析
1. 项目概述:一个“脾气暴躁”的堆垛起重机 在工业现场,最让人头疼的往往不是那些彻底罢工的设备,而是那些“时好时坏”、“看心情工作”的间歇性故障。它们像幽灵一样,在你想复现问题时消失得无影无踪,等你一离开又悄…...
ChatGPT Instagram内容策略失效真相(92%运营者忽略的算法适配层)
更多请点击: https://intelliparadigm.com 第一章:ChatGPT Instagram内容策略失效的底层归因 Instagram 的算法演进与用户行为迁移,正系统性瓦解基于通用大模型(如 ChatGPT)生成的“模板化内容策略”。其失效并非源于…...
将Taotoken作为内部AI中台统一对接各类客户端工具
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 将Taotoken作为内部AI中台统一对接各类客户端工具 设想一个中型研发团队,内部已经引入了Claude Code、OpenClaw等多种A…...
Shoelace自动加载器:终极懒加载Web组件完整指南 [特殊字符]
Shoelace自动加载器:终极懒加载Web组件完整指南 🚀 【免费下载链接】shoelace Shoelace is now Web Awesome. Come see what’s new! 项目地址: https://gitcode.com/gh_mirrors/sh/shoelace Shoelace自动加载器是Shoelace Web组件库中一个革命性…...
Drogon框架数据库连接监控终极指南:性能指标与智能告警机制
Drogon框架数据库连接监控终极指南:性能指标与智能告警机制 【免费下载链接】drogon Drogon: A C14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows 项目地址: https://gitcode.com/gh_mirrors/dr/drogon Drogon是一个基于…...
保姆级教程:用MNN在Android上部署你的第一个图像分类App(从模型转换到实时摄像头识别)
从零构建Android端智能图像分类应用:MNN实战全流程解析 在移动互联网时代,将AI能力嵌入移动端应用已成为提升用户体验的关键。想象一下这样的场景:用户打开手机就能实时识别植物种类、辨别商品真伪,或是自动分类相册中的照片——这…...
