面向对象之_多态_1
目录
一. 多态
多态是什么
二. 多态的构成条件
1. 虚函数
2. 虚函数重写(隐藏)
3. 父类型的引用或者指针调用
4. 多态的特殊情况
1) 子类可以不加 virtual 关键字
2) 协变
三. 关键字
1. virtual
2. final
3. override
四. 多态的原理
1. 虚函数表指针
2. 调用原理
多态是怎么样被调用的?
多态为什么不能是父类的对象调用?
为什么需要是虚函数呢?
五. 总结
一. 多态
多态是什么
多态:简单的说就是不同类型的对象调用相同的函数产生的结果是不同的。
二. 多态的构成条件
-
虚函数重写
-
父类型的指针或者引用调用虚函数
1. 虚函数
虚函数就是一个函数前面加一个关键字 virtual 关键字,这样就是虚函数了,但是虚函数只能是成员函数才能是虚函数,而全局函数不可以成为虚函数。
virtual void fun()
{cout << "fun()" << endl;
}int main()
{return 0;
}
只有成员函数才可以是虚函数。
class A
{
public:virtual void fun(){}
};
这样就是没有问题的。
2. 虚函数重写(隐藏)
我们的父类和子类只有函数三同才可以构成虚函数重写。
三同:函数名相同,参数相同,返回值相同,然后还需要是虚函数。
只有满足三同并且还都是虚函数才能构成重写。
class person
{
public:virtual void buyTicket(){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:virtual void buyTicket(){cout << "void student::buyTicket()" << endl;}
};
上面代码就是一个重写。
3. 父类型的引用或者指针调用
void fun(person& p)
{p.buyTicket();
}int main()
{person p;student s;fun(p);fun(s);return 0;
}
上面就是多态了。
如果我们破坏了里面的任意一个条件,那么就是不构成多态的,我们下面破坏掉虚函数的条件,让父类不是虚函数。
class person
{
public:void buyTicket(){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:virtual void buyTicket(){cout << "void student::buyTicket()" << endl;}
};void fun(person& p)
{p.buyTicket();
}int main()
{person p;student s;fun(p);fun(s);return 0;
}
此时我们的调用就是普通的 person对象 调用 buyTicket 函数。
我们在破坏一个其他的条件,返回值。
class student : public person
{
public:virtual void buyTicket(){cout << "void student::buyTicket()" << endl;}
};void fun(person& p)
{p.buyTicket();
}
此时编译都不通过。
我们在破坏一个参数的条件。
class person
{
public:virtual void buyTicket(int a){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:virtual void buyTicket(){cout << "void student::buyTicket()" << endl;}
};
此时编译也是不通过的,如果改变的是子类的参数,那么编译通过但是调用时不成功的。
4. 多态的特殊情况
在多态里面,是由一些特殊情况的
1) 子类可以不加 virtual 关键字
class person
{
public:virtual void buyTicket(){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:void buyTicket(){cout << "void student::buyTicket()" << endl;}
};
我们的多态也是成功的,所以在多态这里我们的子类时可以不加 virtual 关键字的,但是基类时需要加的。
2) 协变
协变就是参数可以不同,但是我们是有条件的,我们的协变只能是返回父类和子类的指针或者是引用。
class person
{
public:virtual person& buyTicket(){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:virtual student& buyTicket(){cout << "void student::buyTicket()" << endl;}
};
而且我们必选是同时是指针或者是引用,我们也不仅是可以是自己的父类和子类,我们也可以是其他的父类和子类。
class A
{};class B : public A
{};class person
{
public:virtual A& buyTicket(){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:virtual B& buyTicket(){cout << "void student::buyTicket()" << endl;}
};
而我们的返回值必须是父类返回父类,子类返回子类。
class person
{
public:virtual B& buyTicket(){cout << "void person::buyTicket()" << endl;}
};class student : public person
{
public:virtual A& buyTicket(){cout << "void student::buyTicket()" << endl;}
};
三. 关键字
1. virtual
virtual 关键字:
- 虚继承:在继承的时候使用该关键字
- 虚函数:在函数前面加 virtual 关键字
2. final
final 关键字:
- 最终类:在类的后面加 final 表示该类无法被继承
class A final
{};class B : public A
{};
这里就是我们不能对 A 进行继承
3. override
override 关键字:
- 检查是否完成重写:在派生类中使用,加在想要被重写的函数后面
- 静态检查:在编译时静态检查,确保派生类中重写了基类的虚函数
class A
{
public:void fun(){}
};class B : public A
{
public:void fun() override{}
};
许哦一这里只需要完成重写就可以了。
class A
{
public:virtual void fun(){}
};class B : public A
{
public:void fun() override{}
};
四. 多态的原理
1. 虚函数表指针
在前面的菱形虚拟继承继承中,如果有重定义的函数或者变量,那么里面是有一个虚基表的,这个是虚函数表指针,不要弄混了,下面看一下虚函数表指针。
在有虚函数的类中,该类都会有一个虚函数表指针,该指针就是指向该类中的虚函数的。
class A
{
public:virtual void fun(){}int _a;
};int main()
{A a;cout << sizeof(A) << endl;return 0;
}
这里的 sizeof 是8,所以这里的 A 肯定不只有一个 _a 的成员变量,还有一个虚函数表指针,这个是一个指针,所以在 32 位和 64 位下的环境是不同的。
下面1看一下该类的内部是怎么样的。
看一下这个指针里面的内容。
现在 a 这个对象里面只有一个虚函数,所以该表里面只存储一个,而虚函数表指针的本质,就可以理解为一个函数指针数组,该函数指针数组里面存储的就是一个个虚函数,如果还有其他的虚函数,那么还是会放在该类的这个虚函数表里面。
虚函数表:每个类共同使用一个虚函数表。
下面看一下相同类型的对象使用的虚函数表是否相同。
2. 调用原理
多态是怎么样被调用的?
多态是需要父类的对象或者是指针,然后调用重写的虚函数。
在父类的指针或者引用看来,它自己指向的对象模型就是一个父类对象。
class A
{
public:virtual void fun(){cout << "A::fun()" << endl;}int _a;
};class B : public A
{
public:virtual void fun(){cout << "B::fun()" << endl;}int _b;
};int main()
{B b;return 0;
}
这里看一下B 类型对象的对象模型
所以在父类的引用或者指针看来就是一个父类的对象,但是调用为什么会形成多态?
看一下这个虚表指针里面的内容。
B 类型的对象里面的虚表指针里面是重写后的自己的虚函数,所以在调用的时候可以调用到自己的函数。
那么为什么B 类型的对象里面的虚表指针里面是自己的函数地址呢?下面分为3步。
- 在多态中,派生类首先会把基类的虚函数表拷贝下来。
- 如果派生类中对基类的虚函数进行了重写,那么就会将虚函数表中的基类的被重写的虚函数替换成自己的虚函数的地址。
- 如果自己也有自己的虚函数,就将自己的虚函数添加到虚函数表中。
多态为什么不能是父类的对象调用?
多态为什么不能是父类的对象呢?
int main()
{B b;A a = b;
}
现在将b 赋值给a,那么现在的a里面的虚表是父类的虚表还是子类的虚表?
当然是自己的,因为在父子类在进行赋值的时候,虚表是不会进行赋值的,如果虚表进行赋值的话,那么现在的 a 里面的虚表就是B 类型的虚表,那么a 对象调用虚函数的时候是调用的就是派生类的函数了,所以在进行赋值的时候虚表不能赋值,由于虚表在赋值的时候不能不拷贝,所以多态调用的时候不能是父类的对象。
int main()
{B b;A a;b._a = 10;a = b;
}
通过这段代码测试一下,这里将里面的 _a 变量赋值时为例更好的查看。
这里看到虚表时没有变化的。
为什么需要是虚函数呢?
前面说过了,虚函数会放到虚表里面,那么如果不是虚函数的话,那么当然是不会放在虚表里面的,所以如果函数都不在虚表里面即使是父类的指针或者是引用在虚表里面也找不到应该重写后的虚函数,所以也就没法实现多态。
五. 总结
多态
- 多态的调用需要父类的引用或者是指针调用
- 调用的函数必须是虚函数进行重写
- 虚函数重写的条件是三同(函数名相同,返回值,参数)
- 在多态这里子类是可以不加 virtual 的,只要父类加了,那么子类与父类的函数又是三同,就构成多态
- 协变,协变就是返回值可以不同,但是返回值必须是父类返回父类的指针或者是引用,子类必须返回子类的指针或者是引用,而且返回的父子类只要是父子类既可以,不一定是自己的父子类
相关文章:

面向对象之_多态_1
目录 一. 多态 多态是什么 二. 多态的构成条件 1. 虚函数 2. 虚函数重写(隐藏) 3. 父类型的引用或者指针调用 4. 多态的特殊情况 1) 子类可以不加 virtual 关键字 2) 协变 三. 关键字 1. virtual 2. final 3. override 四. 多态的原理 1. 虚…...

Spring学习笔记之spring概述
文章目录 Spring介绍Spring8大模块Spring特点 Spring介绍 Spring是一个轻量级的控制反转和面向切面的容器框架 Spring最初的出现是为了解决EJB臃肿的设计,以及难以测试等问题。 Spring为了简化开发而生,让程序员只需关注核心业务的实现,尽…...

旧项目导入Eclipse时文件夹看起来乱七八糟,无从下手的解决办法(无main或webapp等文件夹)
首先,如果没有main或java/resource/webapp等文件夹,那就自己在src下面创建一个,只要对应关系与我下图左边红框一致即可,创建完之后java文件移到java文件夹下,资源文件例如.properties、老项目的数据源定义.INI文件、日…...

Reinforcement Learning with Code 【Code 2. Tabular Sarsa】
Reinforcement Learning with Code 【Code 2. Tabular Sarsa】 This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation of Rei…...

服务调用---------Ribbon和Feign
目录 1、Ribbon 1.1 Ribbon简介 1.2 Ribbon负载均衡 负载均衡原理 负载均衡策略 Ribbon和Nginx的区别 1.3 服务调用和Ribbon负载均衡实现 2、Feign&openFeign 3、Feign支持的配置 日志功能 连接池 feign-api远程包 1、Ribbon 1.1 Ribbon简介 Ribb…...

app自动化测试之Appium问题分析及定位
使用 Appium 进行测试时,会产生大量日志,一旦运行过程中遇到报错,可以通过 Appium 服务端的日志以及客户端的日志分析排查问题。 Appium Server日志-开启服务 通过命令行的方式启动 Appium Server,下面来分析一下启动日志&#…...

婚庆服务小程序app开发方案详解
开发一款婚庆行业服务小程序有哪些功能呢? 1、选择分类 选择婚庆、婚车、婚宴、司仪、彩妆、婚庆用品、跟拍、摄影等,筛选出对应的商家 2、选择商家 选择分类后,可以选择商家,查看各个商家的详细介绍情况。 3、选择服务套餐 各…...

集合简述
集合ListArrayListLinkedList SetHashSetTreeSet MapHashMapTreeMap 集合与数组的区别 集合 集合是java中的一个容器,可以在里面存放数据,容量可以发生改变 从集合框架结构可以分析得知: 1、集合主要分为Collection和Map两个接口 2、Collecti…...
常见的软件测试面试题汇总
一、 你们的测试流程是怎么样的? 答:1.项目开始阶段,BA(需求分析师)从用户方收集需求并将需求转化为规格说明书,接 下来在项目组领导会组织需求评审。 2.需求评审通过后,BA 会组织项目经理…...

学习笔记|大模型优质Prompt开发与应用课(二)|第二节:超高产文本生成机,传媒营销人必备神器
文章目录 01 文字写作技能的革新,各行各业新机遇四大类常见文字工作新闻记者的一天新闻记者的一天–写策划prompt 新闻记者的一天–排采访prompt生成结果prompt生成结果 大模型加持,文字写作我们如何提效营销创作营销创作-使用预置法为不同平台生成文案p…...
Linux基础-4
1、linux高阶命令 1.1、find 在linux文件系统中,用来查找一个文件放在哪里了。 //举例 find /etc -name "interfaces" //总结: //(1)什么时候用find? //当你知道你要找的文件名,但是你忘记了它被放在哪个目录下&…...
oracle-创建函数
oracle自定义函数 核心提示:函数用于返回特定数据。执行时得找一个变量接收函数的返回值; 语法如下: create or replace function function_name ( argu1 [mode1]datatype1, argu2 [mode2] datatype2, … ) return datatype is begin end; 执行 var v1 varchar2(1…...

【Ansible 的脚本 --- playbook 剧本】
目录 一、playbook 剧本介绍二、示例1、运行playbook2、定义、引用变量 三、使用playbook部署lnmp集群 一、playbook 剧本介绍 playbooks 本身由以下各部分组成 (1)Tasks:任务,即通过 task 调用 ansible 的模板将多个操作组织在…...
ubuntu释放缓存
sudo sysctl vm.drop_caches1 sudo sysctl vm.drop_caches2 sudo sysctl vm.drop_caches3释放页面缓存: $ sudo sysctl vm.drop_caches1释放目录项和索引节点缓存: $ sudo sysctl vm.drop_caches2释放页面缓存、目录项和索引节点缓存: $ sudo…...

实用调试技巧(1)
什么是bug?调试是什么?有多重要?debug和release的介绍。windows环境调试介绍。一些调试的实例。如何写出好(易于调试)的代码。编程常见的错误。 什么是Bug 我们在写代码的时候遇到的一些问题而导致程序出问题的就是Bu…...

uniapp:H5定位当前省市区街道信息
高德地图api,H5定位省市区街道信息。 由于uniapp的uni.getLocation在H5不能获取到省市区街道信息,所以这里使用高德的逆地理编码接口地址接口,通过传key和当前经纬度,获取到省市区街道数据。 这里需要注意的是:**高德…...
自然语言处理从入门到应用——LangChain:提示(Prompts)-[提示模板:部分填充的提示模板和提示合成]
分类目录:《自然语言处理从入门到应用》总目录 部分填充的提示模板 提示模板是一个具有.format方法的类,它接受一个键值映射并返回一个字符串(一个提示),以传递给语言模型。与其他方法一样,将提示模板进行…...

论文笔记--GloVe: Global Vectors for Word Representation
论文笔记--GloVe: Global Vectors for Word Representation 1. 文章简介2. 文章概括3 文章重点技术3.1 两种常用的单词向量训练方法3.2 GloVe3.3 模型的复杂度 4. 文章亮点5. 原文传送门6. References 1. 文章简介 标题:GloVe: Global Vectors for Word Representa…...

day57|● 647. 回文子串 ● 516.最长回文子序列
647. 回文子串 https://leetcode.cn/problems/palindromic-substrings/solution/by-lfool-2mvg/ Given a string s, return the number of palindromic substrings in it. A string is a palindrome when it reads the same backward as forward. A substring is a contiguous…...
docker compose.yml学习
docker compose 安装docker-compose sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composechmod x /usr/local/bin/docker-composeln -s /usr/local/bin/docker-…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...