C++多态的实现原理
【欢迎关注编码小哥,学习更多实用的编程方法和技巧】
1、类的继承
子类对象在创建时会首先调用父类的构造函数
父类构造函数执行结束后,执行子类的构造函数
当父类的构造函数有参数时,需要在子类的初始化列表中显式调用
Child(int i) : Parent("在子类构造函数中的初始化列表进行显式调用父类构造函数")
析构函数调用的先后顺序与构造函数相反
继承与组合的混搭
类中的成员变量可以是其它类的对象(组合)
口诀:先父母,后客人,再自己。
当子类中定义的成员变量与父类中的成员变量同名时
子类依然从父类继承同名成员
在子类中通过作用域分别符::进行同名成员区分
同名成员存储在内存中的不同位置
cout << "Parent::i = " << Parent::i << endl;
cout << "Child::i = " << Child::i << endl;
cout << "Parent::f = " << Parent::f << endl;
子类对象可以当作父类对象使用
子类对象在创建时需要调用父类构造函数进行初始化
子类对象在销毁时需要调用父类析构函数进行清理
先执行父类构造函数,再执行成员构造函数
在继承中的析构顺序与构造顺序对称相反
同名成员通过作用域分辨符进行区分
2、函数的重写
父类中被重写的函数依然会继承给子类
默认情况下子类中重写的函数将隐藏父类中的函数
通过作用域分辨符::可以访问到父类中被隐藏的函数
Parent *p = &child;
p->print();
Parent& rP = child;
rP.print();
打印输出的是父类的函数。
C++编译器支持静态联编,就是在编译阶段就可以确定下来的多态。
对于动态联编,只有在运行时才能确定的对象类型,编译器是不能作判断的,最稳妥的做法就是使用父类的类型进行操作。
C++与C相同,是静态编译型语言
在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象
所以编译器认为父类指针指向的是父类对象(根据赋值兼容性原则,这个假设合理)
由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象
从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数
面向对象的新需求
根据实际的对象类型来判断重写函数的调用
如果父类指针指向的是父类对象则调用父类中定义的函数
如果父类指针指向的是子类对象则调用子类中定义的重写函数
实现了以上的功能就是面向对象中的多态。
多态
根据运行时实际的对象类型表现出不同的行为状态,叫多态。
C++中通过virtual关键字对多态进行支持
使用virtual声明的函数被重写后即可展现多态特性
虚函数
在父类函数声明前面加上virtual关键字,使其成为虚函数。这时,函数就表现出多态性。
函数重载
必须在同一个类中进行
子类无法重载父类的函数,父类同名函数将被覆盖
重载是在编译期间根据参数类型和个数决定调用函数
函数重写
必须发生于父类与子类之间
并且父类与子类中的函数必须有完全相同的原型
使用virtual声明之后能够产生多态,子类在重写时自动成为虚函数
多态是在运行期间根据具体对象的类型决定调用函数
隐藏:
派生类中的函数与基类中的函数同名并且参数相同,但基类函数不是虚函数
派生类中的函数与基类中的函数同名,参数不同,不管基类函数是否是虚函数,基类函数都会被屏蔽。
child.Parent::func(); //使用作用域分别符可以调用
child.func(); //不可直接调用,因为父类的同名函数被隐藏。
3、C++中多态的实现原理
当类中声明虚函数时,编译器会在类中生成一个虚函数表
虚函数表是一个存储类成员函数指针的数据结构
虚函数表是由编译器自动生成与维护的
virtual成员函数会被编译器放入虚函数表中
存在虚函数时,每个对象中都有一个指向虚函数表的指针VPTR
每一个类都会由编译器自动生成一个虚函数表,而且每个类只有唯一一个表。此类生成的每一个对象里面都隐含着一个指向该表的指针。
调用虚函数时,会通过VPTR指针指向的虚函数表中查询该函数,找到入口地址,并调用。这个过程相对比较耗时,因此执行效率相对比较低,因此,没有必要把所有的函数都设计为虚函数。
对象在创建的时候由编译器对VPTR指针进行初始化
只有当对象的构造完全结束后VPTR的指向才最终确定
父类对象的VPTR指向父类虚函数表
子类对象的VPTR指向子类虚函数表
构造函数中调用虚函数无法实现多态。
纯虚函数
面向对象中的抽象类
抽象类可用于表示现实世界中的抽象概念
抽象类是一种只能定义类型,而不能产生对象的类
抽象类只能被继承并重写相关函数
抽象类的直接特征是纯虚函数
纯虚函数是只声明函数原型,而故意不定义函数体的虚函数。
统一的格式:
virtual 返回类型 函数名(参数列表)= 0;
抽象类与纯虚函数
包含着纯虚函数的类叫抽象类
抽象类不能用于定义对象
抽象类只能用于定义指针和引用
抽象中的纯虚函数必须被子类重写
class Shape{public:virtual double area() = 0;};class Rectangle : public Shape{public:Rectangle(double a, double b){m_a = a;m_b = b;}double area(){return m_a * m_b;}private:double m_a;double m_b;};class Circle : public Shape{private:double m_r;public:Circle(double r){m_r = r;}double area(){return 3.14 * m_r * m_r;}};void func(Shape *s){cout << s->area() << endl;}int main(int argc, char *argv[]){Rectangle rect(3,2);Circle c(4);func(&rect);func(&c);return EXIT_SUCCESS;}多态与数组class Parent{protected:int i;public:virtual void func(){cout << "Parent::func()" << endl;}};class Child : public Parent{protected:int j;public:Child(int a, int b){i = a;j = b;}void func(){cout << "i = " << i << " , j = " << j << endl;}};int main(int argc, char *argv[]){Parent *pp = NULL;Child *pc = NULL;Child ca[] = {Child(1,2),Child(3,4),Child(5,6),Child(7,8)};pp = ca;pc = ca;cout << "sizeof(Parent) = " << sizeof(Parent) << endl;cout << "sizeof(Child) = " << sizeof(Child) << endl;cout << setbase(16) << "pp = " << pp << endl;cout << setbase(16) << "pc = " << pc << endl;pp->func();pc->func();pp++;pc++;cout << setbase(16) << "pp = " << pp << endl;cout << setbase(16) << "pc = " << pc << endl;//pp->func();//pc->func();return EXIT_SUCCESS;}
注:Parent类对象占有8个字节,因为需要维护一个虚函数表的指针也占4个字节。同样的,Child对象除自身的变量j以外,还要从父类继承一个变量i,也要维护一个虚函数表的指针,一共12个字节。
不要将多态应用于数组
指针运算是通过指针的类型进行的 (编译时确定)
多态是通过虚函数表实现的 (运行时确定)
虚基类及多重继承
被实际开发经验抛弃的多继承
工程开发中真正意义上的多继承是几乎不被使用的
多重继承带来的代码复杂性远多于其带来的便利
多重继承对代码维护性上的影响是灾难性的
在设计方法上,任何多继承都可以用单继承代替
为了解决从不同途径继承来的同名数据成员造成的二义性问题 , 可以将共同基类设置为虚基类 。 这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝。
class B : virtual public A
{
};
class C : virtual public A
{
};
这就是虚基类的来源。
C++的接口设计
实际工程经验证明
多重继承接口不会带来二义性和复杂性问题
多重继承可以通过精心设计用单继承和接口代替
接口类只是一个功能说明,而不是功能实现 。
子类需要根据功能说明定义功能实现 。
绝大多数面向对象语言都不支持多继承,但都支持接口的概念
C++中没有接口的概念
C++中可以使用纯虚函数实现接口
class Interface
{
public:
virtual void func1() = 0;
virtual void func2(int i) = 0;
virtual void func3(int i, int j) = 0;
};
接口类中只有函数原型的定义,没有任何数据的定义。
相关文章:
C++多态的实现原理
【欢迎关注编码小哥,学习更多实用的编程方法和技巧】 1、类的继承 子类对象在创建时会首先调用父类的构造函数 父类构造函数执行结束后,执行子类的构造函数 当父类的构造函数有参数时,需要在子类的初始化列表中显式调用 Child(int i) : …...
[极客大挑战 2019]PHP--详细解析
信息搜集 想查看页面源代码,但是右键没有这个选项。 我们可以ctrlu或者在url前面加view-source:查看: 没什么有用信息。根据页面的hint,我们考虑扫一下目录看看能不能扫出一些文件. 扫到了备份文件www.zip,解压一下查看网站源代码…...
map用于leetcode
//第一种map方法 function groupAnagrams(strs) {let map new Map()for (let str of strs) {let key str ? : str.split().sort().join()if (!map.has(key)) {map.set(key, [])}map.get(key).push(str)} //此时map为Map(3) {aet > [ eat, tea, ate ],ant > [ tan,…...
CommonJS 和 ES Modules 的 区别
CommonJS 和 ES Modules 的 区别 1. CommonJS 和 ES Modules 区别?1.1 语法差异CommonJS:ES Modules: 1.2. 加载机制CommonJS:ES Modules: 1.3. 运行时行为CommonJS:ES Modules: 1.4. 兼容性和使用场景Com…...
科技为翼 助残向新 高德地图无障碍导航规划突破1.5亿次
今年12月03日是第33个国际残疾人日。在当下科技发展日新月异的时代,如何让残障人士共享科技红利、平等地参与社会生活,成为当前社会关注的热点。 中国有超过8500万残障人士,其中超过2400万为肢残人群,视力障碍残疾人数超过1700万…...
Flink四大基石之Time (时间语义) 的使用详解
目录 一、引言 二、Time 的分类及 EventTime 的重要性 Time 分类详述 EventTime 重要性凸显 三、Watermark 机制详解 核心原理 Watermark能解决什么问题,如何解决的? Watermark图解原理 举例 总结 多并行度的水印触发 Watermark代码演示 需求 代码演示ÿ…...
Spring WebFlux与Spring MVC
Spring WebFlux 是对 Spring Boot 项目中传统 Spring MVC 部分的一种替代选择,主要是为了解决现代 Web 应用在高并发和低延迟场景下的性能瓶颈。 1.WebFlux 是对 Spring MVC 的替代 架构替代: Spring MVC 使用的是基于 Servlet 规范的阻塞式模型…...
【深度学习基础】一篇入门模型评估指标(分类篇)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀深度学习_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. 模…...
D80【 python 接口自动化学习】- python基础之HTTP
day80 requests请求加入headers 学习日期:20241126 学习目标:http定义及实战 -- requests请求加入headers 学习笔记: requests请求加入headers import requestsurlhttps://movie.douban.com/j/search_subjects params{"type":…...
⽂件操作详解
⽬录 一 文件操作的引入 1 为什么使⽤⽂件? 2 什么是⽂件? 3 文件分类(1 从⽂件功能的⻆度来分类:程序⽂件/数据⽂件 2根据数据的组织形式:为⽂本⽂件/⼆进制⽂件) 二 ⽂件的打开和关闭 1 …...
双高(高比例新能源发电和高比例电力电子设备)系统宽频振荡研究现状
1 为什么会形成双高电力系统 (1)新能源发电比例增加 双碳计划,新能源革命,可再生能源逐步代替传统化石能源,未来新能源发电将成为最终能源需求的主要来源。 (2)电力电子设备数量增加 为了实…...
TorchMoji使用教程/环境配置(2024)
TorchMoji使用教程/环境配置(2024) TorchMoji简介 这是一个基于pytorch库,用于将文本分类成不同的多种emoji表情的库,适用于文本的情感分析 配置流程 从Anaconda官网根据提示安装conda git拉取TorchMoji git clone https://gi…...
使用 Python 中的 TripoSR 根据图像创建 3D 对象
使用 Python 中的 TripoSR 根据图像创建 3D 对象 1. 效果图2. 步骤图像到 3D 对象设置环境导入必要的库设置设备创建计时器实用程序上传并准备图像处理输入图像生成 3D 模型并渲染下载.stl 文件展示结果3. 源码4. 遇到的问题及解决参考这篇博客将引导如何使用Python 及 TripoSR…...
Spring 框架中AOP(面向切面编程)和 IoC(控制反转)
在 Spring 框架中,AOP(面向切面编程)和 IoC(控制反转)是两个核心概念,它们分别负责不同的功能。下面我将通过通俗易懂的解释来帮助你理解这两个概念。 IoC(控制反转) IoC 是 Inver…...
电机瞬态分析基础(7):坐标变换(3)αβ0变换,dq0变换
1. 三相静止坐标系与两相静止坐标系的坐标变换―αβ0坐标变换 若上述x、y坐标系在空间静止不动,且x轴与A轴重合,即,如图1所示,则为两相静止坐标系,常称为坐标系,考虑到零轴分量,也称为αβ0坐标…...
Open3D (C++) 生成任意3D椭圆点云
目录 一、算法原理1、几何参数2、数学公式二、代码实现三、结果展示一、算法原理 1、几何参数 在三维空间中,椭圆由以下参数定义: 椭圆中心点 c = ( x 0 , y 0 , z...
5.利用Pandas以及Numpy进行数据清洗
1、缺失值处理 import pandas as pd import numpy as np#创建一张7行5列带有缺失值的表,表中的数据0-100随机生成,索引是python1. df pd.DataFrame(datanp.random.randint(0,100,size(7,5)), index [i for i in pythonl])df.iloc[2,3] Nonedf.iloc[4…...
@Bean注解详细介绍以及应用
目录 一、概念二、应用(一)代码示例1、首先创建一个简单的 Java 类User2、然后创建一个配置类AppConfig3、在其他组件中使用Bean创建的 bean4、通过 Spring 的ApplicationContext来获取UserService并调用其方法 (二)bean的方法名详…...
基于SpringBoot的预制菜销售系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
从 EXCEL 小白到 EXCEL 高手的成长之路
在职场与日常生活中,Excel 作为一款强大的数据处理与分析工具,扮演着不可或缺的角色。无论是初学者还是资深职场人士,掌握 Excel 技能都能极大地提高工作效率。那么,从一个 Excel 小白蜕变成为 Excel 高手,究竟需要多久…...
【纸飞机串口调试工具】数值显示器及四则运算
目录 纸飞机串口工具介绍软件下载适用场合功能介绍 纸飞机串口工具介绍 纸飞机一款性能强劲且专业的串口/网络/HID调试助手,具有多窗口绘图、关键字高亮、数据分窗和数据过滤等众多功能,可以极大的方便嵌入式开发人员的调试过程。本文介绍数值显示器的四…...
浅谈volatile
volatile有三个特性: (1)可见性 (2)不保证原子性 (3)禁止指令重排 下面我们一一介绍 (一)可见性 volatile的可见性是说共享变量只要修改,就可以被其他线…...
Python3 爬虫 Scrapy的使用
安装完成Scrapy以后,可以使用Scrapy自带的命令来创建一个工程模板。 一、创建项目 使用Scrapy创建工程的命令为: scrapy startproject <工程名> 例如,创建一个抓取百度的Scrapy项目,可以将命令写为: scrapy s…...
多线程篇-4--重点概念1(volatile,Synchronized,内存屏障,MESI协议)
一、volatile (1)、简述 volatile是java提供的一个关键字,英文意思为不稳定的。 可以保障被声明对象的可见性和一定程度上的有序性,但不能保证操作的原子性。 当一个变量被声明为volatile时,意味着该变量的值会直接从…...
本地学习axios源码-如何在本地打印axios里面的信息
1. 下载axios到本地 git clone https://github.com/axios/axios.git 2. 下载react项目, 用vite按照提示命令配置一下vite react ts项目 npm create vite my-vue-app --template react 3. 下载koa, 搭建一个axios请求地址的服务端 a.初始化package.json mkdir koa-server…...
1、SpringBoo中Mybatis多数据源动态切换
我们以一个实例来详细说明一下如何在SpringBoot中动态切换MyBatis的数据源。 一、需求 1、用户可以界面新增数据源相关信息,提交后,保存到数据库 2、保存后的数据源需要动态生效,并且可以由用户动态切换选择使用哪个数据源 3、数据库保存了多个数据源的相关记录后,要求…...
【浏览器】缓存与存储
我是目录 浏览器缓存为什么需要浏览器缓存?对浏览器的缓存机制的理解协商缓存和强缓存的区别强缓存协商缓存 点击刷新按钮或者按 F5、按 CtrlF5 (强制刷新)、地址栏回车有什么区别? 浏览器本地存储前端储存的方式有哪些࿱…...
积鼎科技携手西北工业大学动力与能源学院共建复杂多相流仿真联合实验室
11月26日,复杂多相流仿真联合实验室揭牌仪式及技术研讨活动在西北工业大学动力与能源学院成功举办。复杂多相流仿真联合实验室是由西北工业大学动力与能源学院牵头,携手上海积鼎信息科技有限公司与三航铸剑(西安)科技发展有限公司…...
5. langgraph实现高级RAG (Adaptive RAG)
1. 数据准备 from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import WebBaseLoader from langchain_community.vectorstores import Chromaurls ["https://lilianweng.github.io/posts/2023-06-23-age…...
Postman设置接口关联,实现参数化
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 postman设置接口关联 在实际的接口测试中,后一个接口经常需要用到前一个接口返回的结果, 从而让后一个接口能正常执行,这…...
网络舆情报告/软件网站关键词优化
转自:https://blog.csdn.net/qq_39231769/article/details/96183991 入门 IT 第一步,来一个干净的电脑系统吧? (装机需谨慎,系统盘必须格式化,其他风险自测。) 本教程提供两种重装系统方式&…...
交警队网站开发/关键词优化排名公司
英语作文我的理想每个人都有不同的理想,并朝着自己的理想努力。那么,下面是小编给大家分享的英语作文我的理想,希望大家喜欢。英语作文我的理想1When I got settled, the total use of the microwave to do their own things to eat. One day…...
郑州小程序开发多少钱/宁波seo营销
C中的::的作用 2018-06-08 13:47:46 一米阳光-ing 阅读数 8036更多 分类专栏: C/C (1)作用域限定符,当在类体中直接定义函数时,不需要在函数名字的前面加上类名,但是在类体外实现函数定义的时候,必须加上类名并且加…...
网站规划和建设的步骤/建立网站平台需要多少钱
一、什么是Selenium selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Grid)。Selenium的核心Seleni…...
wordpress 在线生成app/宁波seo外包方案
文章目录0. 系统自带的内核树1. 环境配置2. 下载源码3. 构建准备4. 构建内核5. 安装模块附录参考链接0. 系统自带的内核树 有时,安装的系统已经自带了Linux内核树,足够用来编译驱动程序了。 自带的内核树通常位于 /lib/modules/<系统内核版本>/…...
做的网站.如何在局域网内访问/无锡百姓网推广
昨天开始接到用户提报,说是iprocess没有同步个人账号。这个简单,在我们本身的程序上跑一下就可以添加。所以很简单运行一下。com.staffware.sso.data.vException: SAL system error what?报错了?我晕,当时简单的认为&a…...