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

从静态多态、动态多态到虚函数表、虚函数指针

        多态(Polymorphism)是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息做出不同的响应。多态性使得可以使用统一的接口来操作不同类的对象,从而提高了代码的灵活性和可扩展性。

一、多态的表现形式

1. 静态多态(编译时多态)

        静态多态主要通过函数重载、运算符重载以及模板来实现。通过不同的参数列表、泛型类来选择合适的函数。

重载

#include <iostream>void print(int a) {std::cout << "Integer: " << a << std::endl;
}void print(double a) {std::cout << "Double: " << a << std::endl;
}int main() {print(10);    // 调用 void print(int)print(10.5);  // 调用 void print(double)return 0;
}

模板

#include <iostream>template <typename T>
void print(T a) {std::cout << "Value: " << a << std::endl;
}int main() {print(10);    // 生成 void print<int>(int)print(10.5);  // 生成 void print<double>(double)return 0;
}
2. 动态多态(运行时多态)

        动态多态主要由虚函数和继承来实现,根据对象的实际类型来调用相应的函数。

#include <iostream>class Base {
public:virtual void print() const {    // 如果这里将virtual注释掉,下面两个都会输出"Base"std::cout << "Base" << std::endl;}virtual ~Base() {} // 虚析构函数
};class Derived : public Base {
public:void print() const override {std::cout << "Derived" << std::endl;}
};int main() {Base* basePtr = new Base();Base* derivedPtr = new Derived();basePtr->print();     // 输出 "Base"derivedPtr->print();  // 输出 "Derived"delete basePtr;delete derivedPtr;return 0;
}

        上面的代码中又提到了把virtual注释掉的情况,这涉及到了 “静态类型” “动态类型” 。在这一部分结束之后会讲到。

二、虚函数表、虚函数指针

        虚函数通过运行时的动态绑定,来实现在子类中重写基类的函数。虚函数的原理可以通过虚函数表、虚函数指针来解释。

1. VTable和vptr

        ·每个包含虚函数的类,都有一个虚函数表VTable,是一个指向函数指针的数组。

        ·每个对象创建之后,会有一个虚函数指针vptr,指向类的虚函数表VTable。

        ·当调用虚函数时,会通过vptr查找VTable,然后调用对应的函数。

2. 构造函数不能是虚函数

        在对象创建时,编译器会给对象的vptr赋值,然后再调用构造函数,如果构造函数是虚函数,此时就陷入了死循环。

3. 析构函数可以是虚函数

        通过将基类的析构函数声明为虚函数,可以确保在通过基类指针删除子类对象时,调用到子类的析构函数,合适地释放资源。

#include <iostream>class Base {
public:virtual ~Base() {std::cout << "Base destructor" << std::endl;}
};class Derived : public Base {
public:~Derived() {std::cout << "Derived destructor" << std::endl;}
};int main() {Base* ptr = new Derived();delete ptr; // 先调用 Derived 的析构函数,然后再调用 Base 的析构函数return 0;
}

三、静态类型、动态类型

        静态类型:是指对象在声明时的类型,在编译期已既定。

        动态类型:一个指针、引用目前指向的对象的类型,在运行时确定的。

再来看我们刚才的代码。

        在函数调用时,虚函数会根据动态类型来调用,而普通函数就通过静态类型

#include <iostream>class Base {
public:/*virtual*/ void print() const {    // 将virtual注释掉,下面两个都会输出"Base"std::cout << "Base" << std::endl;}
};class Derived : public Base {
public:    void print() const /*override*/ {    // override和上面的virtual对应std::cout << "Derived" << std::endl;}
};int main() {Base* basePtr = new Base();        // 静态类型Base,动态类型BaseBase* derivedPtr = new Derived();  // 静态类型Base,动态类型DerivedDerived* thirdPtr = new Derived(); // 静态类型Derived,动态类型DerivedbasePtr->print();     // 输出 "Base"derivedPtr->print();  // 输出 "Base"thirdPtr->print();    // 输出 "Derived"delete basePtr;delete derivedPtr;delete thirdPtr;return 0;
}

四、static_cast和dynamic_cast的安全与否

1. static_cast

static_cast是一种显式类型转换,主要用于已知的类型转换。

  • 向上转型(从派生类指针或引用转换为基类指针或引用)是安全的,因为派生类对象可以被视为基类对象的一个特例。
  • 基本类型转换(如 int 到 double)也是安全的。
  • 不进行运行时检查,因此在某些情况下可能会导致未定义行为,特别是当进行向下转型时。
2. dynamic_cast

dynamic_cast是一种运行时类型检查的类型转换,主要用于多态类型之间的转换。

  • 向上转型(从派生类指针或引用转换为基类指针或引用)是安全的。
  • 向下转型(从基类指针或引用转换为派生类指针或引用)是安全的,因为它会在运行时检查类型的有效性。
  • 运行时检查类型安全,如果转换不成功,会返回 nullptr(对于指针)或抛出 std::bad_cast 异常(对于引用)。

 

相关文章:

从静态多态、动态多态到虚函数表、虚函数指针

多态&#xff08;Polymorphism&#xff09;是面向对象编程中的一个重要概念&#xff0c;它允许不同类的对象对同一消息做出不同的响应。多态性使得可以使用统一的接口来操作不同类的对象&#xff0c;从而提高了代码的灵活性和可扩展性。 一、多态的表现形式 1. 静态多态&…...

用 Pygame 实现一个乒乓球游戏

用 Pygame 实现一个乒乓球游戏 伸手需要一瞬间&#xff0c;牵手却要很多年&#xff0c;无论你遇见谁&#xff0c;他都是你生命该出现的人&#xff0c;绝非偶然。若无相欠&#xff0c;怎会相见。 引言 在这篇文章中&#xff0c;我将带领大家使用 Pygame 库开发一个简单的乒乓球…...

基于大数据可视化的化妆品推荐及数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…...

Java项目实战II基于Java+Spring Boot+MySQL的汽车销售网站(文档+源码+数据库)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字化时…...

数学基础 -- 微积分最优化之一个最简单的例子

微积分中的一个最简单的最优化例子 问题描述 假设你有一条长度为 10 米的栅栏&#xff0c;你需要围成一个矩形的鸡舍&#xff0c;使得围成的面积最大。求这个矩形的长和宽应是多少&#xff0c;以使得面积最大。 步骤 设定变量&#xff1a; 设矩形的长为 x x x 米&#xff0…...

kubernetes K8S 结合 Istio 实现流量治理

目录 1.Istio介绍&#xff1f; 1.1 Istio是什么&#xff1f; 1.2 Istio流量管理 1.2.1 熔断 1.2.2 超时 1.2.3 重试 2.Istio架构 3.istio组件详解 3.1 Pilot 3.2 Envoy 3.3 Citadel 3.4 Galley 3.5 Ingressgateway 3.5 egressgateway 扩展、k8s1.23及1.23以下版…...

Selenium with Python学习笔记整理(网课+网站持续更新)

本篇是根据学习网站和网课结合自己做的学习笔记&#xff0c;后续会一边学习一边补齐和整理笔记 非常推荐白月黑羽的学习网站&#xff1a; 白月黑羽 (byhy.net) https://selenium-python.readthedocs.io/getting-started.html#simple-usage WEB UI自动化环境配置 (推荐靠谱…...

1.随机事件与概率

第一章 随机时间与概率 1. 随机事件及其运算 1.1 随机现象 ​ 确定性现象&#xff1a;只有一个结果的现象 ​ 确定性现象&#xff1a;结果不止一个&#xff0c;且哪一个结果出现&#xff0c;人们事先并不知道 1.2 样本空间 ​ 样本空间&#xff1a;随机现象的一切可能基本…...

Redis结合Caffeine实现二级缓存:提高应用程序性能

本文将详细介绍如何使用CacheFrontend和Caffeine来实现二级缓存。 1. 简介 CacheFrontend: 是一种用于缓存的前端组件或服务。通俗的讲&#xff1a;该接口可以实现本地缓存与redis自动同步&#xff0c;如果本地缓存&#xff08;JVM级&#xff09;有数据&#xff0c;则直接从本…...

【LLM】Ollama:本地大模型 WebAPI 调用

Ollama 快速部署 安装 Docker&#xff1a;从 Docker 官网 下载并安装。 部署 Ollama&#xff1a; 使用以下命令进行部署&#xff1a; docker run -d -p 11434:11434 --name ollama --restart always ollama/ollama:latest进入容器并下载 qwen2.5:0.5b 模型&#xff1a; 进入 O…...

SpringBoot集成阿里easyexcel(二)Excel监听以及常用工具类

EasyExcel中非常重要的AnalysisEventListener类使用&#xff0c;继承该类并重写invoke、doAfterAllAnalysed&#xff0c;必要时重写onException方法。 Listener 中方法的执行顺序 首先先执行 invokeHeadMap() 读取表头&#xff0c;每一行都读完后&#xff0c;执行 invoke()方法…...

使用ELK Stack进行日志管理和分析:从入门到精通

在现代IT运维中&#xff0c;日志管理和分析是确保系统稳定性和性能的关键环节。ELK Stack&#xff08;Elasticsearch, Logstash, Kibana&#xff09;是一个强大的开源工具集&#xff0c;广泛用于日志收集、存储、分析和可视化。本文将详细介绍如何使用ELK Stack进行日志管理和分…...

前端框架对比与选择

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&#x1f495;&#x1f495;&#x1f495; 目…...

Springboot jPA+thymeleaf实现增删改查

项目结构 pom文件 配置相关依赖&#xff1a; 2.thymeleaf有点类似于jstlel th:href"{url}表示这是一个链接 th:each"user : ${users}"相当于foreach&#xff0c;对user进行循环遍历 th:if进行if条件判断 {变量} 与 ${变量}的区别: 4.配置好application.ym…...

【YashanDB知识库】yashandb执行包含带oracle dblink表的sql时性能差

本文内容来自YashanDB官网&#xff0c;具体内容请见https://www.yashandb.com/newsinfo/7396959.html?templateId1718516 问题现象 yashandb执行带oracle dblink表的sql性能差&#xff1a; 同样的语句&#xff0c;同样的数据&#xff0c;oracle通过dblink访问远端oracle执行…...

效率工具推荐 | 高效管理客服中心知识库

人工智能AI的广泛应用&#xff0c;令AI知识库管理已成为优化客服中心运营的核心策略之一。一个高效、易用且持续更新的知识库不仅能显著提升客服代表的工作效率&#xff0c;还能极大提升客户的服务体验。而高效效率工具如HelpLook&#xff0c;能够轻松搭建AI客服帮助中心&#…...

综合实验1 利用OpenCV统计物体数量

一、实验简介 传统的计数方法常依赖于人眼目视计数&#xff0c;不仅计数效率低&#xff0c;且容易计数错误。通常现实中的对象不会完美地分开&#xff0c;需要通过进一步的图像处理将对象分开并计数。本实验巩固对OpenCV的基础操作的使用&#xff0c;适当的增加OpenCV在图像处…...

[Redis][主从复制][上]详细讲解

目录 0.前言1.配置1.建立复制2.断开复制3.安全性4.只读5.传输延迟 2.拓扑1.一主一从结构2.一主多从结构2.树形主从结构 0.前言 说明&#xff1a;该章节相关操作不需要记忆&#xff0c;理解流程和原理即可&#xff0c;用的时候能自主查到即可主从复制&#xff1f; 分布式系统中…...

【算法】leetcode热题100 146.LRU缓存. container/list用法

https://leetcode.cn/problems/lru-cache/description/?envTypestudy-plan-v2&envIdtop-100-liked 实现语言&#xff1a;go lang LRU 最近最少未使用&#xff0c;是一种淘汰策略&#xff0c;当缓存空间不够使用的时候&#xff0c;淘汰一个最久没有访问的存储单元。目前…...

[论文总结] 深度学习在农业领域应用论文笔记13

文章目录 1. Downscaling crop production data to fine scale estimates with geostatistics and remote sensing: a case study in mapping cotton fibre quality &#xff08;Precision Agriculture &#xff0c;2024&#xff0c; IF5.585&#xff09;背景方法结果结论个人总…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...