C++ | 虚函数
在 C++ 面向对象编程领域,多态性堪称核心概念,而虚函数则是实现运行时多态的关键所在。
一、虚函数的概念与作用
1.1 什么是虚函数
虚函数是 C++ 中用于实现动态多态的成员函数。在基类中使用virtual关键字声明虚函数后,派生类能够重写(override)该函数。这样一来,当通过基类指针或引用调用此函数时,实际执行的将是派生类中的函数版本。
class Animal {
public:virtual void makeSound() {cout << "Animal sound!" << endl;}
};class Dog : public Animal {
public:void makeSound() override {cout << "Woof!" << endl;}
};
// 使用示例
Animal* animal = new Dog();
animal->makeSound();
上述代码中,Animal类声明了虚函数makeSound,Dog类继承自Animal类并重写了makeSound函数。通过Animal类型的指针调用makeSound函数时,实际调用的是Dog类中的makeSound函数,输出 “Woof!”。
1.2 虚函数的作用
- 运行时多态:根据对象的实际类型来决定调用哪个函数,实现了动态绑定,提高了代码的灵活性和可扩展性。
- 代码扩展性:允许新增派生类,而无需修改基类代码,符合开闭原则,使程序更易于维护和升级。
二、虚函数表(vTable)机制
2.1 虚函数表的结构
每个包含虚函数的类都拥有一个虚函数表(vTable),它本质上是一个函数指针数组,存储着该类所有虚函数的地址。编译器会为每个对象添加一个隐藏指针(vPtr),该指针指向其所属类的虚函数表。
2.2 动态绑定的实现
当通过基类指针调用虚函数时,程序会按以下步骤执行:
- 通过对象的 vPtr 找到虚函数表。
- 根据函数在表中的偏移量定位具体函数地址。
- 执行派生类的函数实现。
三、哪些函数可以是虚函数
虚函数的调用依赖虚函数表指针,同一个类所有对象拥有同一个虚函数表,但是每个对象都有自己独立的虚表指针。所以虚函数的调用需要借用this指针指向虚函数表。
3.1 普通成员函数
这是最常见的虚函数形式。只需在基类的成员函数声明前加上virtual关键字,就可以允许派生类对其进行重写。
class Base {
public:
virtual void func() { /*... */ }
};
3.2 析构函数
特别强调,基类的析构函数必须声明为虚函数。这是为了确保在释放派生类对象时,能够正确调用派生类和基类的析构函数,避免内存泄漏。
class Base {
public:
virtual ~Base() { /* 释放基类资源 */ }
};
class Derived : public Base {
public:
~Derived() override { /* 释放派生类资源 */ }
};
Base* obj = new Derived();
delete obj;
3.3 纯虚函数
纯虚函数通过= 0语法进行定义,它使类成为抽象类,强制要求派生类必须实现该函数。
class Shape {
public:
virtual void draw() = 0;
};
四、哪些函数不能是虚函数
4.1 构造函数
构造函数不能是虚函数。原因在于,对象构造时需要先确定其类型,而虚函数机制依赖于已初始化的 vPtr,在构造函数执行期间,vPtr 尚未建立,无法实现虚函数调用。以下代码无法编译:
4.2 静态成员函数
静态函数属于类,而非对象,不依赖 vPtr。因此,静态成员函数不能声明为虚函数。
4.3 友元函数
友元函数不属于类的成员函数,没有继承特性,也就不存在虚函数的概念。
4.4 内联函数
从技术上来说,内联函数可以声明为虚函数,但inline关键字仅是对编译器的一种建议,要求编译器将函数体直接嵌入到调用处,以提高执行效率。而虚函数的调用需要在运行时动态确定函数地址,这与内联函数的编译时展开特性相悖。因此,当虚函数声明为inline时,编译器通常会忽略该关键字。
4.5 全局函数和普通函数
虚函数必须是类的成员函数,全局函数和普通函数不属于任何类,因此不能声明为虚函数。
五、虚函数的注意事项
- 性能开销:虚函数调用涉及查表过程,相较于普通函数调用,会有一定的性能损耗。
- 内存占用:每个对象需要额外存储 vPtr,通常占用 4/8 字节的内存空间,这在对象数量较多时,可能会对内存使用产生一定影响。
- 设计建议:若基类可能被继承,析构函数应声明为虚函数,以确保资源的正确释放。
六、总结
- 可以是虚函数:普通成员函数、析构函数、纯虚函数。
- 不能是虚函数:构造函数、静态成员函数、友元函数、全局函数和普通函数,以及声明为虚函数但无实际意义的内联函数。
虚函数表是实现动态多态的基石,深入理解其机制,能够帮助我们更好地优化代码结构,提升程序性能。在实际编程中,应根据具体需求合理使用虚函数,充分发挥 C++ 面向对象编程的优势。
相关文章:
C++ | 虚函数
在 C 面向对象编程领域,多态性堪称核心概念,而虚函数则是实现运行时多态的关键所在。 一、虚函数的概念与作用 1.1 什么是虚函数 虚函数是 C 中用于实现动态多态的成员函数。在基类中使用virtual关键字声明虚函数后,派生类能够重写&#x…...
单元测试整理
在国外软件开发中,单元测试必不可少,但是国内并不太重视这一块,一个好的单元测试可以提前发现很多问题,也减去和测试battle的时间 Spring单元测试 JUnit4 RunWith 指明单元测试框架 e.g. RunWith(SpringJUnit4ClassRunner.cla…...
Delphi语言的软件工程
Delphi语言的软件工程 引言 在软件工程的历史长河中,Delphi语言作为一种快速应用程序开发(RAD)的工具,凭借其高效的开发环境和强大的编程能力,一直在软件开发领域占有一席之地。本文将探讨Delphi语言的历史背景、特性…...
XSS攻击(跨站脚本攻击)详解与实战
文章目录 一、什么是XSS?二、XSS分类与场景三、XSS攻击实战流程四、CTF中的XSS利用五、XSS防御方案六、绕过过滤的常见技巧七、实战练习资源 一、什么是XSS? XSS(Cross-Site Scripting) 是一种通过向网页注入恶意脚本(…...
【C++指南】类和对象(十):const成员函数
💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 目录 引言 一、const成员函数的定义与语法 1. 基本语法 2. 底层原理 二、const成员函数的作用与约束…...
数值分析与科学计算导引——误差与算法举例
文章目录 第一章 数值分析与科学计算导引1.1 数值分析的对象、作用与特点数值分析的对象数值分析的作用数值分析的特点 1.2 数值计算的误差误差分类误差与有效数字数值运算的误差估计 1.3 算法举例秦九韶算法求多项式值开根号迭代算法牛顿切线加权平均的松弛技术 第一章 数值分…...
ubuntu安装docker 无法拉取问题
sudo docker run hello-world [sudo] ubuntu 的密码: Unable to find image hello-world:latest locally docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": context deadline exceeded (Client.Timeout exceeded while awai…...
【C++项目】Rpc通信框架设计
目录 Rpc远程调用的思想 项目框架设计 服务端模块划分 网络通信模块 Network 应用层通信协议模块 Protocol 消息分发处理模块 Dispatcher 远程调用路由功能模块 RpcRouter 编辑 发布订阅功能模块 Publish-Subscribe 服务注册/发现/上线/下线功能模块 Registry-Disc…...
八股取士--dockerk8s
一、Docker 基础 Docker 和虚拟机的区别是什么? 答案: 虚拟机(VM):虚拟化硬件,每个 VM 有独立操作系统,资源占用高,启动慢。Docker:容器化应用,共享宿主机内核…...
Autojs: 使用 SQLite
例子 let db new SQLiteUtil("/sdcard/A_My_DB/sqlite.db");db.fastCreateTable("user_table",{name: "",online: false,},["name"] // 设置 name 为唯一, 重复项 不会添加成功 );// 新增数据的 ID let row_id db.insert("use…...
思科、华为、H3C常用命令对照表
取消/关闭 思科no华为undo华三undo 查看 思科show华为display华三display 退出 思科exit华为quit华三quit 设备命名 思科hostname华为sysname华三sysname 进入全局模式 思科enable、config terminal华为system-view华三system-view 删除文件 思科delete华为delete华…...
解决 `pip is configured with locations that require TLS/SSL` 错误
问题描述 在使用 pip 安装 Python 包时,可能会遇到以下错误: WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.这意味着 Python 的 ssl 模块未正确安装或配置,导致 p…...
2025-arXiv-OmniThink:通过思考扩展机器写作的知识边界
arXiv | https://arxiv.org/abs/2501.09751 GitHub | https://github.com/zjunlp/OmniThink 项目主页 | https://zjunlp.github.io/project/OmniThink/ ModelScope 在线 Demo | https://www.modelscope.cn/studios/iic/OmniThink 摘要: 大语言模型驱动的机器写作通…...
【广州大学主办,发表有保障 | IEEE出版,稳定EI检索,往届见刊后快至1个月检索】第二届电气技术与自动化工程国际学术会议 (ETAE 2025)
第二届电气技术与自动化工程国际学术会议 (ETAE 2025) The 2nd International Conference on Electrical Technology and Automation Engineering 大会官网:http://www.icetae.com/【更多详情】 会议时间:2025年4月25-27日 会议地点:…...
机器学习:01数学基础教程
函数 极限 按照一定次数排列的一列数:“,“,…,"…,其中u 叫做通项。 对于数列{Un}如果当n无限增大时,其通项无限接近于一个常数A,则称该数列以A为极限或称数列收敛于A,否则称数列为发散, 极限值 左…...
仿叮咚买菜鸿蒙原生APP
# DingdongShopping 这是一个原生鸿蒙版的仿叮咚买菜APP项目 鸿蒙Next发布至今已经有一年多的时间了,但有时候我们想要实现一些复杂的功能或者效果,在开发文档上查阅一些资料还是比较费时的,有可能还找不到我们想要的内容。而社会层面上分享…...
WordPress“更新失败,响应不是有效的JSON响应”问题的修复
在使用WordPress搭建网站时,许多人在编辑或更新文章时,可能会遇到一个提示框,显示“更新失败,响应不是有效的JSON响应”。这个提示信息对于不了解技术细节的用户来说,太难懂。其实,这个问题并不复杂&#x…...
kotlin的onFailure: () -> Unit
在Kotlin中,onFailure: () -> Unit表示一个没有参数且返回类型为Unit的函数。 在Kotlin中,Unit类型用于表示那些没有返回值的函数。具体来说,() -> Unit表示一个没有参数的函数,其返回类型为Unit。这种函数通常用于表示…...
通过网线将Keysight DSOX4154A示波器信号传输至电脑的Step
一、硬件连接 连接网线 使用标准以太网线(Cat5e或更高)连接示波器背面的 LAN端口 至电脑或同一局域网的交换机/路由器。 二、示波器网络配置 进入网络设置菜单 点击示波器前面板右上角 【Utility】 → 【I/O】 → 【LAN Settings】。 配置IP地址 自…...
midjourney 一 prompt 提示词
midjourney 不需要自然语言的描述,它只需要关键词即可。 一个完整的Midjourney prompt通常包括三个部分 图片提示(Image Prompts)、文本提示(Text Prompt)和参数(Parameters)。 1、图片提示(…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
