更好的理解c++中的虚函数和静态多态以及动态多态
1.虚函数(Virtual Function)
在c++ 中, 虚函数是定义在基类中的函数,但是它可以在派生类中进行重写(Override) 。
通过在基类中通过virtual 关键字声明函数 , 你创建了一个可以在任何派生类中特别实现的接口。 当你有一个指针指向基类或者引用, 并通过这个指针或者引用调用虚函数时, c++ 运行时会根据指针或者引用 实际指向的对象来调用适当的函数。 这个过程是在运行时动态发生的, 这也就是所谓的动态绑定或晚绑定 。
2.多态(Polymorphism)
多态是一个通用的概念 , 指的是可以通过同一个接口访问不同类型对象的能力 。
在c++ 中 多态通常通过虚函数来实现, 当你使用基类的指针或者引用调用一个虚函数时, 实际上会执行派生类版本的函数, 这取决于指针或者引用实际指向的对象类型, 多态允许你编写通用的代码, 这些代码可以与任何从基类派生的类的对象一起工作, 而无需在编译时知道确切的派生类型 。
3. 例子
上面的不太好理解 : 举个简单的例子, 有一天你到餐厅吃饭,服务员给你一张菜单(基类)进行点菜,菜单上有各种食物(派生类) , 但你只需要看菜单就可以做出选择,而不需要知道每种食物是如何准备的
在c++ 中多态就相当于这个菜单 , 它允许你使用一个**通用的接口(基类的指针或引用)**来执行可能有多种不同实现的操作,这意味着我们在写代码的时候不必对象的确切类型, 只需要知道它能干什么 。
其中,虚函数就相当于菜单上的各种食物, 我们可以在基类中声明(virtual), 并且在派生类中重新定义(override)
3.1 代码实现
#include <iostream>
class Food {
public: virtual void prepare(){std::cout << "prepare some food " << std::endl;}
};
class noodele :public Food {
public:void prepare () override {std::cout << "this is your noodel " << std::endl;}
};
class water :public Food {
public:void prepare() override {std::cout << "this is your water " << std::endl;}
};void eat(Food* food)
{ //接口要是 : 基类的指针或者引用food->prepare(); //实现多态
}
int main()
{Food* myfood = new water();eat(myfood); delete myfood;
}
4.注意
虚函数虽然非常好用, 但是在使用虚函数的时候,并不是所有函数都得定义成虚函数,因为实现虚函数是有代价的,需要注意以下几方面的:
- **虚析构函数:**如果你的类有虚函数,也应该提供一个虚析构函数,为了确保通过基类指针删除派生类的对象的时候,能够调用正确的析构函数
- 内存和性能考虑 : 使用虚函数会增加每个对象的内存开销,以此每个对象需要一个额外的指针来访问虚函数表(v-table) ,此外,虚函数的调用比非虚函数慢,因为需要额外的间接寻址
- 虚函数的继承: 一旦在基类中定义了虚函数,它在派生类中自动成为虚函数, 即便没有 virtual 关键字
5. 静态多态和动态多态
- 静态多态中, 所有的类型检查和函数调用解析都是在编译时完成的,一次静态多态不会引入运行时的开销
- 动态多态 :动态动态主要是运行时进行的 主要通过虚函数实现的 ,在动态多态中, 函数的调用不是在编译时解析的,而是在运行时,当你通过基类的指针或者引用在调用一个虚函数时, c++ 运行时会根据对象的实际类型来确定调用那个函数 。
5.1 函数重载和模板
- 函数重载就是指你写了多个重名的函数,但是传入的参数类型或者个数不一样,编译器会根据你传入的参数类型或者参数个数来决定调用那个函数 。
- 模板就是一种能够让你的函数或者类能够处理不同数据类型的方法, 你写一次代码,编译器会根据你使用的具体类型来生成多个代码版本
就比如说使用模板实现不同类型的数据交换
#include <iostream>template <typename T>
void swap(T& a, T& b) {T temp = a;a = b;b = temp;
}int main() {int i = 1, j = 2;swap(i, j); // 交换两个intstd::cout << "i: " << i << ", j: " << j << std::endl;double x = 3.14, y = 1.59;swap(x, y); // 交换两个doublestd::cout << "x: " << x << ", y: " << y << std::endl;return 0;
}
5.2总结也就是:
静态多态的类型早已知晓 , 多态性在编译时通过函数重载和模板实现,没有运行开销
动态多态它的类型可能未知, 多态性在运行时通过虚函数实现,这涉及到类型识别,有一定的性能开销
6. 什么函数不能声明为虚函数
- 普通函数 : 普通函数只能被overload, 不能被override,声明为虚函数也没有意义,因此编译器会在编译时绑定函数
- 构造函数: 构造函数是为了明确初始化对象成员才产生的, 然而virtual function 主要是为了再不完全了解细节的情况下也能处理对象, 另外virtual function 函数是在不同类型的对象产生不同的对象, 现在对象还没产生,如何使用virtual 函数来完成你想完成的动作 。
- 静态成员函数: 静态成员函数是不依赖于类的实例,而虚函数是要通过对象的虚表(vtable)来调用
- 主函数:主函数是程序的入口点,以此不会被声明为虚函数 。
相关文章:
更好的理解c++中的虚函数和静态多态以及动态多态
1.虚函数(Virtual Function) 在c 中, 虚函数是定义在基类中的函数,但是它可以在派生类中进行重写(Override) 。 通过在基类中通过virtual 关键字声明函数 , 你创建了一个可以在任何派生类中特别实现的接口…...
MybatisPlus之新增操作并返回主键ID
在应用mybatisplus持久层框架的项目中,经常遇到执行新增操作后需要获取主键ID的场景,下面将分析及测试过程记录分享出来。 1、MybatisPlus新增方法 持久层新增方法源码如下: public interface BaseMapper<T> extends Mapper<T> …...
工程(十四)——ubuntu20.04 PL-VINS
博主创建了一个科研互助群Q:772356582,欢迎大家加入讨论。这是一个科研互助群,主要围绕机器人,无人驾驶,无人机方面的感知定位,决策规划,以及论文发表经验,以方便大家很好很快的科研…...
C复习-结构struct+bit field+union
参考: 里科《C和指针》 结构的声明 struct {int a;char b; } x; struct {int a;char b; } y[20], *z;// 会报错,因为z和x虽然都没有名字,但是并不是一个东西 z &x;struct SIMPLE {int a;char b; }; // 这样就对了,因为名字匹…...
1 快速了解Paimon数据湖核心原理及架构
1.1 什么是Apache Paimon Apache Paimon的前身属于Flink的子项目:Flink Table Store。 目前业内主流的数据湖存储项目都是面向批处理场景设计的,在数据更新处理时效上无法满足流式数据湖的需求,因此Flink社区在2022年的时候内部孵化了 …...
chrome v3开发插件实现所有网站允许跨域
场景: chrome 插件 升级到v3后,原来修改请求响应都变成异步,即无法同步拦截来修改请求响应。 在v3中也不支持修改请求响应内容。 问题:如何在chrome v3中允许其他网站跨域呢。 方式一:禁用chrome跨域,禁…...
unity Holoens2开发,使用Vuforia识别实体或图片 触发交互
建议:先看官方文档 我使用的utniy 版本:Unity 2021.3.6f1 官方建议:混合现实工具包简介 - 设置项目并使用手势交互 - Training | Microsoft Learn 配置了正确工具的 Windows 10 或 11 电脑Windows 10 SDK 10.0.18362.0 或更高版本安装了 U…...
从零开始搭建微服务(一)
构建项目父工程 添加公共核心模块 安装nacos 安装nacos nacos 文档地址: https://nacos.io/zh-cn/docs/what-is-nacos.html 本文使用版本2.2.2 下载地址:https://github.com/alibaba/nacos/archive/refs/tags/2.2.2.zip 使用nacos 我们下载是源代码 解…...
一种可以实现安全便捷文件摆渡的跨网文件安全交换软件
为了保护数据的安全性和完整性,很多企业都采用了内外网物理隔离的方式,防止核心数据泄露或被恶意篡改。然而,这也给企业内部或与外部合作伙伴之间的文件交换带来了很多不便和挑战。如何在保证数据安全的前提下,实现跨网文件的快速…...
『 MySQL数据库 』数据库基础之表的基本操作
文章目录 创建表🗡查看表🗡✒ 查看表内所有信息(描述\表结构等)✒ 根据条件查看表内数据✒ 查看表的具体详细信息: 修改表🗡✒ 修改表名:✒ 修改表的存储引擎、编码集(字符集和校验集):✒ 表内插入数据:insert into✒ 在表中新添一个字段(列)…...
如何提高40%的Docker构建时间
1. 背景 在产品开发中构建docker镜像,随着时间的推移,会变得越来越大,构建时间也越来越长。我的目标是构建时间不超过 5 分钟。 2. 遵循Dockerfile的最佳实践 我们首先确保Dockerfile文件遵循Docker官方的最佳实践,具体做法有: 尽量使用官方的基础镜像,Docker推荐使用…...
真正解决jellyfin硬解码转码
前段时间入手一个DS423集成显卡UHD600,搭了一个jellyfin,发现网上关于硬解码的教程基本都存在问题,没有真正解决我的硬解码问题。经过一系列分析修改,最终实现硬解码。先贴效果图: 下载安装jellyfin这里就不叙述&#…...
声音训练数据集哪里找?中文、英文
一般找数据集的都是需要训练底膜的,大家git上找的开源项目大多是预训练模型。预训练就是别人已经训练好的底膜,你在他的基础上进行调整。而我们训练如果他这个模型不理想是需要训练底膜的。 找的方式是从git开源上找 中文 推荐MockingBird,…...
springboot中如何同时操作同一功能
问题描述 测试阶段,由于存在某一功能的同时操作,该功能还是入库逻辑,此时若不进行处理,会造成插入表中多条重复数据,为此该问题需要修复。 解决办法 在接口开始进行对是否存在某个key值的判断,若不存在&…...
YOLOWeeds: 用于棉花生产系统中多类杂草检测的 YOLO 目标检测器的新基准
YOLOWeeds: A novel benchmark of YOLO object detectors for multi-class weed detection in cotton production systems 摘要1、介绍2、总结 摘要 过度依赖除草剂控制杂草,加速了杂草的抗除草剂进化,引起了对环境、食品安全和人类健康的日益关注。自动…...
Vue3:自定义图标选择器(包含 SVG 图标封装)
文章目录 一、准备工作(在 Vue3 中使用 SVG)二、封装 SVG三、封装图标选择器四、Demo 效果预览: 一、准备工作(在 Vue3 中使用 SVG) 本文参考:https://blog.csdn.net/houtengyang/article/details/1290431…...
NIO讲解
一:什么是NIO? 二:NIO三大组件 1. channel channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入…...
react中jest配置,解决node_modules报错esm无法解析的问题
重点关注: transformIgnorePatterns: [ "/node_modules/(?!(?:jmfe)/)", ], moduleNameMapper: { "\\.(css|less|scss|sss|styl)$": "jest-css-modules" } 并安装jest-css-modules(npm i --save-dev jest-css-mo…...
Qt6,使用 UI 界面完成命令执行自动化的设计
一、需要完成的功能 在子对话框(CmdChildQt)中,点击 “执行” 按钮,将多个命令行指令,依次输入到父对话框(CmdQt)的编辑框中并且执行,要求如下: 在前一个命令执行完成后&…...
Apache Maven;会话技术
Apache Maven是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建、报告和文档。 Maven模型有: 项目对象模型、依赖管理模型、插件 会话技术: 会话:…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
