C++中的静态和动态多态

2023-10-28

之前学过继承,子类继承父类的属性,多态就是基于继承而来的,我们在如果只用继承,那么子类继承父类的各种属性在编译环节,就已经被确认了,导致代码不灵活。如果继承下来的某个子类不支持某种问题的解决,那么父类就需要重新编写代码,这样这个子类ok了,其他子类却有可能出现问题。

多态的好处:灵活,提高代码的可复用性。

1、多态的分类

1、静态多态:函数重载和运算符重载属于静态多态,复用函数名(编译期多态);

2、动态多态:派生类和虚函数实现运行时多态(运行期多态)。

函数重载就不必多说了,就是函数名的复用;运算符重载也类似于函数重载,相当于把符号的功能扩大了,同一个符号或者函数,能够实现多种功能,它们都是在编译的时候绑定了,以后都不能改变了,所以叫编译器多太。

2、动态多态的实现

我们以汉堡为例,汉堡为父类,鸡腿堡和牛肉保都继承了汉堡类。

代码:

#include<iostream>
using namespace std;

class baseHamburger//父类------汉堡类
{
public:

	void Material()
	{
		cout << "汉堡的配方为:面包、酱汁、蔬菜、肉饼"<<endl ;
	}
};

class chickenHamburger:public baseHamburger//子类1------鸡腿堡类
{
public:

	void Material()
	{
		cout << "汉堡的配方为:面包、酱汁、蔬菜、鸡肉饼" << endl;
	}
};

class beefHamburger:public baseHamburger//子类2------牛肉堡类
{
public:

	void Material()
	{
		cout << "汉堡的配方为:面包、酱汁、蔬菜、牛肉饼" << endl;
	}
};

int main()
{
	chickenHamburger p1;
	p1.Material();

	beefHamburger p2;
	p2.Material();
	
}

从代码可知,我们父类和2个子类内存在3个同名的函数Material(),我们创建p1和p2,他们都是默认调用类内的Material()函数,而不是调用父类的Material()函数,在程序编译的时候就确认了Material()函数的地址。如果我们想要调用父类的Material()函数,那么只需要加作用域就行。这也是我们最常见的情况。

如果我们这样写

#include<iostream>
using namespace std;

class baseHamburger//父类------汉堡类
{
public:

	void Material()
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、肉饼" << endl;
	}
};

class chickenHamburger:public baseHamburger//子类1------鸡腿堡类
{
public:

	void Material()
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、鸡肉饼" << endl;
	}
};

class beefHamburger :public baseHamburger//子类2------牛肉堡类
{
public:

	void Material()
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、牛肉饼" <<endl;
	}
};

//创建一个吃的函数
void eat(baseHamburger & Hamburger)
{
	cout << "我吃的"; 
	Hamburger.Material();
	
}

int main()
{
	chickenHamburger p1;
	eat(p1);

	beefHamburger p2;
	eat(p2);		
}

 

 我们创建一个吃的eat()函数,函数参数为父类对象,函数体为父类对象指向和子类同名的函数,

此时,编译器默认调用了父类的Material()函数,为什么呢?

1、我们明明创建的是子类对象,那应该调用的是子类的Material()呀!

2、传入eat()函数的参数是父类对象,那应该就是调用父类的Material()呀!

是不是感觉有歧义?

那怎么解决呢?

只需要在父类的Material()函数前加上virtual关键字就可以解决问题。

class baseHamburger//父类------汉堡类
{
public:

	virtual void Material()//虚函数
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、肉饼" << endl;
	}
};

加上virtual关键字后函数就变成了虚函数,程序运行的时候才确定Material()函数的地址。

有的同学可以说,我直接创建几个不同的函数名不就行了?

这样确实可以,但是你别忘了这个问题是在同名函数,我们要复用函数名前提下提出来的。

而且就算你创建很多个不同的函数名,那代码量不就上来了?且每一个eat()函数的参数都要额外写一个子类对象,函数体实现也就变得复杂了。

我们的目的是传入什么对象,那么就调用什么对象的函数,这也是动态多态的好处。

3、 动态多态的满足条件

1、有继承关系;
2、子类重写父类中的虚函数。

动态多态使用:
父类指针或引用指向子类对象,就像我们的eat()函数一样。

 4、多态内部原理

当我们继承了父类中的函数的时候,那仅仅是继承了这个函数,其内部是通过虚函数表指针(vfptr)的和虚函数表(vftable)来控制的,vfptr又指向vftablevftable内存放了所有父类的函数地址,vfptr就指向这些地址,所以子类的内部就固定存在父类的一份vfptrvftable拷贝,这是最一般的情况。

但是当我们将父类的函数改为虚函数的时候,且在子类重写父类的虚函数,那就不一样了,当我们用父类指针指向子类对象的时候,vftable中同名函数的作用域就从父类变成的子类,相当于把父同名类函数的地址改为子类同名函数的地址。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中的静态和动态多态 的相关文章

  • 求 a 范围内的 pow(a^b)modN

    对于给定的b and N以及一系列a say 0 n 我需要找到ans 0 n 1 where ans i 没有a s为此pow a b modN i 我在这里搜索的是可能的重复pow a b modN对于一系列a 以减少计算时间 例子 i
  • 在 2 个 .c 文件之间共享函数

    dir1有dir2 file1 c和file1 h dir2 有 file2 c 现在 如果我想在 file2 c 中访问 file1 c 中定义的函数 我需要在 file1 h 中声明它并在 file2 c 中包含 file1 h 这是一
  • 在子目录中构建共享库

    我正在尝试构建一个使用一些 C 代码的 R 包 我有一个编译为可执行文件的 C 库 可以从命令行调用 有一个与之关联的 Makefile 我正在尝试获取信息here http cran r project org doc manuals R
  • 运行时两个注册之间的简单注入器基于动态上下文的注入

    我有一个使用 Simple Injector 进行命令处理程序注册的中介应用程序 并且注入和处理程序均已设置并完美运行 class DoWashingCommandHandler IRequestHandler
  • 外部剃刀视图看不到外部模型

    我对外部剃刀视图有疑问 在我的项目中 我有主 mvc Web 程序集和动态加载的外部类库程序集 来自 DB 及其自己的控制器 视图和模型 这些程序集在运行时不会直接引用和加载 我能够通过为控制器创建自定义控制器工厂 为视图创建自定义虚拟路径
  • C# Visual Studio 动态代码片段

    我正在开发一个 WinForms 项目 每天都会执行一些重复性的任务 所以我认为创建代码片段 https msdn microsoft com en us library ms165394 v vs 110 aspx会帮助我 但它仅适用于固
  • 多态性中基类缺少虚拟析构函数 = 资源泄漏?

    我们知道 如果要多态地使用基类 则需要将基类的析构函数指定为 virtual 否则程序中可能会出现资源泄漏 因为只会调用基类析构函数 而不会调用派生对象析构函数 我们还知道构造函数 析构函数纯粹是初始化 未初始化构造 而operator n
  • 在 Windows 服务中使用 OleDb 从 Excel 读取数据?

    免责声明 我知道这是一种不好的做事方式 这是我们与客户的唯一选择 Problem 我们需要每隔 x 时间从 Excel 文件读取数据 数据通过第三方 Excel 插件不断变化 应用程序的环境是 Windows XP SP1 和 Net 2
  • 在 C/C++ 中绘制填充椭圆的简单算法

    在SO上 找到了以下绘制实心圆的简单算法 for int y radius y lt radius y for int x radius x lt radius x if x x y y lt radius radius setpixel
  • 使用私有构造函数的 C# 单元测试类?

    好吧 我刚刚收到一个作业 我必须对具有私有构造函数的类执行单元测试 现在 当所有方法也都是非静态时 我该如何在不初始化类的情况下进行单元测试 有什么方法可以对具有私有构造函数的类进行单元测试 无需反射 如果您无法将类公开 您仍然可以通过以下
  • UWP - 绑定枚举差异

    我遇到了一个非常有趣的问题 假设 UWP 应用中有以下 XAML 页面内容
  • WPF MVVM后台打印数据绑定问题

    我正在使用 wpf mvvm 开发一个销售点应用程序 在交易生命周期的许多阶段 都会在后台打印收据 我已经使用其他示例在后台生成和打印收据 我正在后台打印一个 UserControl 一切看起来都很棒 然后 我为该控件创建了 ViewMod
  • 除法时的小数舍入误差 (C#)

    我基本上有四个数字 比如 100 200 300 400 我需要计算概率为 100 100 200 300 400 200 100 200 300 400 等等在 当我使用小数数据类型来存储这些概率时 由于舍入问题 它们不会达到 1 在不使
  • 为什么 ASP.Net MVC Range 属性采用类型?

    我只是想知道为什么范围验证属性可以采用类型和两个字符串作为参数 这是为了根据枚举或类似的东西验证字符串吗 另外 我想做的是找到一种简单的方法来验证必须出现在枚举中的 3 个字符的字符串 有什么建议吗 谢谢 亚历克斯 我确实发现你提到的 Ra
  • 合并大文件的最佳方法是什么?

    我必须合并数千个大文件 每个大约 200MB 我想知道合并这些文件的最佳方法是什么 行将有条件地复制到合并文件中 可以使用 File AppendAllLines 或使用 Stream CopyTo 吗 使用 File AppendAllL
  • 如何进行平衡组捕获?

    假设我有这个文本输入 tes tR R abc aD mnoR xyz 我想提取 ff 输出 R abc R xyz D mnoR xyz R R abc aD mnoR xyz 目前 我只能使用平衡组方法提取组内的内容 如中所示msdn
  • Task.Delay 到底是如何工作的?

    他们说 Task Delay 是一个异步 Thread Sleep 为了测试这一点 我写了下面的代码 我希望立即打印 One 然后 3 秒后将打印结果变量 15 2 秒后 将打印 Two 但似乎并非如此 一 不会立即打印 3 秒后打印 On
  • 64 位随机生成器种子

    我目前正在运行一个具有 8 个以上管道 线程 的多线程模拟应用程序 这些管道运行非常复杂的代码 该代码取决于种子生成的随机序列 然后该序列被归结为单个 0 1 我希望在将种子从主线程传递到处理管道后 这种 随机处理 具有 100 的确定性
  • 如何以一对一/零关系更新员工和身份用户

    我正在尝试更新员工记录 也想更新身份用户 如果我先单独更新身份用户 例如 UserManager Update user Context Entry employee State System Data Entity EntityState
  • Json.net 将数字属性序列化为字符串

    我正在使用 JsonConvert SerializeObject 序列化模型对象 服务器期望所有字段都是字符串 我的模型对象具有数字属性和字符串属性 我无法向模型对象添加属性 有没有办法将所有属性值序列化为字符串 我必须只支持序列化 而不

随机推荐

  • gcc命令中参数c和o混合使用的详解

    操作系统 windows xp 软件 msys 编译器 gcc gcc c a c 编译成目标文件a o gcc o a a o 生成执行文件a exe gcc a c 生成执行文件a exe gcc o a c a c 编译成目标文件a
  • qml添加qmldir文件步骤

    1 写自定义控件 2 编写qmldir文件 3 在pro文件中添加模块路径 4 在mian cpp中加载qml之前添加模块路径 5 qml中引用自定义qml模块 6 效果如图 参考 参考 https blog csdn net qq 165
  • 机器学习量化应用:用回归策略预测价格

    我们已经知道 监督学习主要就是分类和回归两种方法 本文以支持向量机 support vector machine SVM 来说明 如何采取机器学习中回归方法来预测股票价格 这在传统量化中是根本不可能实现的 在机器学习领域却能达到50 以上的
  • 【QT专栏】QT中实现多线程的四种方式和线程同步

    目录 一 继承QThread 1 基本概念 2 操作流程 二 继承QObject 推荐 1 基本概念 2 操作流程 三 继承QRunnable 配合QThreadPool实现多线程 1 外界通信 2 QMetaObject invokeMe
  • ARM NOEN vfmaq_laneq_f32与vextq_f32指令例子

    vfmaq laneq f32是乘法运算相关指令 vextq f32是取数据相关指令 具体功能用文字描述比较麻烦 直接看个列子一下就懂了 所以在这里记录下来 float32x4 t sum vdupq n f32 0 sum 0 0 0 0
  • element的table组件二次封装,实现动态表头

    封装element的table组件 让其实现动态表头 由于后端传递过来的数据是表头跟数据分开的 而element的table组件是固定死表头的 跟ant design不一样 这怎么搞 只能自己二次封装了 封装思路 1 参照ant desig
  • p5.js炫酷背景动态js特效代码

    下载地址 p5 js炫酷背景动态特效代码 dd
  • 生产管理系统MES详细功能介绍

    MES通过集成各种功能模块 实现了生产过程的全面监控 优化和管理 MES系统在生产过程中被广泛应用 彻底改变了传统的生产方式 MES系统主要有哪些功能模块呢 小编将为大家详细介绍 实时数据采集与监控 MES系统通过连接各种传感器和设备 实时
  • C++开发环境搭建_Visual Studio

    环境搭建步骤 l 下载软件 l 安装软件 l 运行软件 1 下载软件 在百度搜索 visual studio 选择 如下图中的选项 进入Visual Studio 官网后 选择 下载Windows版 并选择Community 2017 社区
  • javafx集成Sqlite工具类,包含增删改查范例

    javafx集成Sqlite工具类 包含增删改查范例 技术分享交流 qq群 835259695 package com hq utils import com hq database entity CollectionBox import
  • 算法练习:707 设计链表(2022-09-23)

    707 设计链表 来源 力扣 LeetCode 链接 https leetcode cn problems design linked list 设计链表的实现 您可以选择使用单链表或双链表 单链表中的节点应该具有两个属性 val和next
  • SmartImageView的简单使用

    SmartImageView主要是为了加速从网上加载图片 支持根据URL地址加载图片 支持异步加载图片 支持图片缓存等 下载地址 http loopj com android smart image view 下载完成后拷贝到项目下的lib
  • nginx反向代理解决vue打包后运行产生的跨域问题

    代理简介 正向代理 客户端明确服务端地址 服务端接收请求时只清楚来自哪个代理服务 反向代理 隐藏服务端信息 访问者并不知道自己访问的时一个地址 反向实现 1 下载nginx 2 修改nginx conf文件 server server 监听
  • 解析excel的坑

    1 解析excel的时候因调用的方法不同导致解析excel的时候数据有时会少一行 hssfSheet getLastRowNum 最后一行行标 比行数小1 hssfSheet getRow k getLastCellNum 获取列数 比最后
  • C++音视频开发从放弃到入门(基于FFmpeg+OpenCV)

    前言 音视频开发一定要学C 吗 答案是肯定的 虽然其它语言也能搞音视频开发 甚至使用起来更简单 但 语言越高级 离真相就越远 当你的功能需求日益增多 程序的性能需求越来越迫切 你想进一步了解程序实现的细节时 使用其它语言往往会面临 无法解决
  • Pinely Round 2 (Div. 1 + Div. 2) A~D

    A Channel 题意 有n个订阅者 a个初始在线人数 q个上下线情况 问是否一定或有可能所有订阅者都阅读了新的帖子 思路 同时在线人数等于n时 一定都阅读了 输出YES 初始在线人数加上所有的上线人数 所有的 号 大于等于n的话输出MA
  • STL- 常用算法(拷贝和替换,算术生成,集合算法)

    目录 1 常用拷贝和替换算法 1 1copy 容器内指定范围的元素拷贝到另一容器中 1 2replace 将容器内指定范围的旧元素修改为新元素 1 3 replace if 将区间内满足条件的元素 替换成指定元素 1 4 swap 互换两个
  • Docker安装redis集群

    文章目录 1 Redis集群介绍 2 Redis 集群的数据分片 3 Redis 集群的主从复制模型 4 docker搭建Redis集群 3主3从 5 主从容错切换迁移案例 6 主从扩容案例 7 主从缩容案例 1 Redis集群介绍 Red
  • 时序预测

    时序预测 MATLAB实现PSO GRU 粒子群优化门控循环单元 时间序列预测 目录 时序预测 MATLAB实现PSO GRU 粒子群优化门控循环单元 时间序列预测 预测效果 基本介绍 模型介绍 PSO模型 GRU模型 PSO GRU模型
  • C++中的静态和动态多态

    之前学过继承 子类继承父类的属性 多态就是基于继承而来的 我们在如果只用继承 那么子类继承父类的各种属性在编译环节 就已经被确认了 导致代码不灵活 如果继承下来的某个子类不支持某种问题的解决 那么父类就需要重新编写代码 这样这个子类ok了