虚函数、纯虚函数、多态
一.虚函数
在基类的函数前加上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…...
LaaS LLM as a service
LaaS LLM as a service 核心构成GPT 产业链如何进行商业化LLM(Large Language Model) 发展和趋势LLM(Large Language Model) 对于行业公司的分层LLM(Large Language Model) 的机遇和挑战 LaaS LLM as a service 核心构成 计算:算力模型:算法输入&…...
数据结构与算法(一)数组的相关概念和底层java实现
一、前言 从今天开始,笔者也开始从0学习数据结构和算法,但是因为这次学习比较捉急,所以记录的内容并不会过于详细,会从基础和底层代码实现以及力扣相关题目去写相关的文章,对于详细的概念并不会过多讲解 二、数组基础…...
歌曲推荐《最佳损友》
最佳损友 陈奕迅演唱歌曲 《最佳损友》是陈奕迅演唱的一首粤语歌曲,由黄伟文作词,Eric Kwok(郭伟亮)作曲。收录于专辑《Life Continues》中,发行于2006年6月15日。 2006年12月26日,该曲获得2006香港新城…...
多元共进|科技促进艺术发展,助力文化传承
科技发展助力文化和艺术的传播 融合传统与创新,碰撞独特魅力 一起来了解 2023 Google 开发者大会上 谷歌如何依托科技创新 推动艺术与文化连接 传承和弘扬传统文化 自 2011 年成立以来,谷歌艺术与文化致力于提供体验艺术和文化的新方式,从生成…...
Java集合(Collection、Iterator、Map、Collections)概述——Java第十三讲
前言 本讲我们将继续来讲解Java的其他重要知识点——Java集合。Java集合框架是Java编程语言中一个重要的部分,它提供了一套预定义的类和接口,供程序员使用数据结构来存储和操作一组对象。Java集合框架主要包括两种类型:一种是集合(Collection),存储一个元素列表,…...
topscoding主题库模板题
目录 模板题 【模板题】分因数(P1101) 【模板题】区间素数 III(P1113) 进制转换 III (任意转任意) (P2463) AB Problem(高精度加法) A-B Problem(高精度减法&…...
Linux--进程间通讯--FIFO(open打开)
1. 什么是FIFO FIFO命名管道,也叫有名管道,来区分管道pipe。管道pipe只能用于有血缘关系的进程间通信,但通过FIFO可以实现不相关的进程之间交换数据。FIFO是Linux基础文件类型中的一种,但是FIFO文件在磁盘上没有数据块,…...
哪里可以了解轻量的工作流引擎?
如果想要实现高效率的办公,可以使用轻量的工作流引擎低代码技术平台。随着工作量日益繁重起来,传统的办公制作方式已经无法满足现实需要的,采用轻量级的表格制作工具,就能在无形中缓解办公压力,创造更高效、灵活、优质…...
lvs负载均衡、LVS集群部署
四:LVS集群部署 lvs给nginx做负载均衡项目 218lvs(DR 负载均衡器) yum -y install ipvsadm(安装这个工具来管理lvs) 设置VIP192.168.142.120 创建ipvsadm的文件用来存放lvs的规则 定义策略 ipvsadm -C //清空现有…...
如何应对核心员工提离职?
最近一年互联网行情不好,很多大厂都在裁员,但裁员并不是不要人做事了。原来你这个岗位10个人做,企业有钱赚养得起,现在企业不怎么赚钱了,只能养4个人了。那么会有六个被裁掉。这时候对企业价值最大的4个人会被留下。也…...
wordpress 远程媒体库/seo整站优化方案
GridLayout是一种非常简单的布局,它的每个组件的大小都相等。这里不许多说,直接上代码和图片说明/** GridLayoutDemo.java requires no other files.*/import java.awt.Container;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;imp…...
网站app封装怎么做/武汉seo价格
//修改版,加入错误信息反馈<?phpheader(Content-type:text/html;charsetutf-8);$cnn new mysqli(localhost, root, root, test); //加了die()居然没有代码提示,蛋疼if($cnn->connect_errno) {die(连接数据库失败: . $cnn->connect_error)…...
深圳市住房和城乡建设局网站/网络营销的背景和意义
前言 Oracle数据库的日期函数是十分强大的,而且也比较的多。笔者将之整理下来供日后的参考 使用。于自己便利,也于别人便利! 常用日期型函数 1、Sysdate: 当前的日期和时间select Sysdate from dual; 2、Last_day()…...
传奇怎么做充值网站/搜索引擎优化的名词解释
上图一共有5个区间,分别是[0,2]、[2,4]、[8,11]、[7,11]、[15,18]。如果要求这些区间合并后区间的大小,有两种简单的方法。 方法一:比较每两个区间的范围,如果两个区间有交集,则合并它们。最后所有区间会合并成几个离散…...
网站开发职业类别代码/查看浏览过的历史记录百度
Linux中的文件,特别是日志文件,特别大了不好打开,或者要把文件放到有文件大小限制的载体上,可以用split命令来切割成小文件 文件分割 split命令有两种方式: 指定行数来切割 split -l 300 log.txt newfile每个文件3…...
网站技术维护/威海网站制作
这是一个功能的示例: 潜在会员可以通过下面的屏幕进行注册。 页面的顶端列出新会员注册的三个步骤,以及当前所处的步骤;在页面的左端是成功交友三步曲;右边是注册帐户表单。 会员输入资料后,单击注册时我们需要进行以下…...