【C++】多态 ① ( 类型兼容性原则与函数重写 | “ 多态 “ 引入 | 函数重写 )

文章目录

  • 一、类型兼容性原则与函数重写
    • 1、" 多态 " 引入
    • 2、函数重写
    • 3、类型兼容性原则的几类情况
    • 4、父类与子类示例
    • 5、父类指针 指向 父类对象 / 子类对象
    • 6、父类引用 指向 父类对象 / 子类对象
  • 二、完整代码示例 - 类型兼容性原则与函数重写
    • 1、代码示例
    • 2、执行结果





一、类型兼容性原则与函数重写




1、" 多态 " 引入


在面向对象中 , " 多态 " 是 设计模式 的基础 , 是 软件框架 的基础 ;


面向对象的 三大特征 是逐步递进的 , 封装 -> 继承 -> 多态 ;

  • 封装 : 将 成员变量 和 成员方法 封装到 类中 , 是一切的基础 ; 拿到类对象后 , 就可以调用其中的 成员变量 和 成员方法 ;
  • 继承 : 类在 封装 的基础上 , 可以进行继承操作 , 子类 继承 父类的 成员 , 可以复用之前写的代码 ;
  • 多态 : 在 继承 的基础上 , 才能讨论 多态 的概念 ;

多态 与 继承 正好相反 ,

  • 继承 是 复用 之前写的代码 ;
  • 多态 是 复用 之后写的代码 ;

2、函数重写


函数重写 : 同时 在 子类 和 父类 中 , 定义 函数原型 相同 的 函数 , 就是 " 函数重写 " , 子类 重写 父类 中的 函数 ;


父类 中 被子类 重写的 函数 , 仍然被 子类 所继承 ;

在 默认的情况下 , 子类 会 隐藏 父类中 被重写的函数 ,

如果想要 显示调用 父类 的 被重写的函数 , 可以使用 域作用符 父类名称 :: 被重写的函数() 的方式进行调用 ;


3、类型兼容性原则的几类情况


被重写的 函数 , 遇到 类型兼容性原则 时 , 调用的 函数 是 子类重写的函数 , 还是 父类的原有函数 ;


下面根据如下几种情况进行讨论 :

  • 父类对象 和 子类对象 调用 重写的函数 ;
  • 父类指针 指向 父类对象 / 子类对象 调用 重写函数 的执行效果 ;
  • 父类引用 指向 父类对象 / 子类对象 调用 重写函数 的执行效果 ;
  • 父类指针 作为函数参数 , 分别传入 父类对象 / 子类对象 地址 , 查看调用 重写函数 的执行效果 ;
  • 父类引用 作为函数参数 , 分别传入 父类对象 / 子类对象 , 查看调用 重写函数 的执行效果 ;

4、父类与子类示例


在 父类 和 子类 中 , 都定义了 print 函数 , 子类 重写 父类的 该函数 ;

// 父类
class Parent {
public:
	Parent(int a)
	{
		x = a;
		cout << "调用父类构造函数" << endl;
	}

	void print()
	{
		cout << "父类 : x = " << x << endl;
	}
public:
	int x;
};

// 子类
class Child : public Parent {
public:
	// 在子类构造函数初始化列表中 调用 父类构造函数
	Child(int a, int b) : Parent(a)
	{
		y = b;
		cout << "调用子类构造函数" << endl;
	}

	// 子类重写父类的 print 函数
	void print()
	{
		cout << "子类 : x = " << x << " , y = " << y << endl;
	}
public:
	int y;
};

5、父类指针 指向 父类对象 / 子类对象


父类 指针 指向 父类对象 , 执行 被子类重写的函数 , 调用的是 父类的 函数 ;

父类 指针 指向 子类对象 , 执行 被子类重写的函数 , 调用的 仍然是 父类的 函数 ;


指针的类型是什么类型 , 调用的就是什么类型的函数 ,

指针类型是 父类 类型 , 那么即使指向子类对象 , 最后调用的也是 父类的成员 ;


代码示例 :

	// 定义父类指针
	Parent* p = NULL;

	// 定义 父类 和 子类对象
	Parent parent(1);
	Child child(1, 2);

	// 3. 将 p 指针指向 父类对象
	// 通过 p 指针 调用指向对象的 print 函数
	// 结果 - `父类 : x = 1`
	p = &parent;
	p->print();

	// 4. 将 p 指针指向 子类对象
	// 通过 p 指针 调用指向对象的 print 函数
	// 结果 - `父类 : x = 1`
	// 虽然将 子类对象 地址赋值给了 p 指针 
	// 但是 调用的 函数仍然是 父类的 print 函数
	// 这是 类型兼容性原则 导致的结果
	p = &child;
	p->print();

6、父类引用 指向 父类对象 / 子类对象


父类 引用 指向 父类对象 , 执行 被子类重写的函数 , 调用的是 父类的 函数 ;

父类 引用 指向 子类对象 , 执行 被子类重写的函数 , 调用的 仍然是 父类的 函数 ;


引用的类型是什么类型 , 调用的就是什么类型的函数 ,

引用类型是 父类 类型 , 那么即使指向子类对象 , 最后调用的也是 父类的成员 ;


代码示例 :

	// 定义父类指针
	Parent* p = NULL;

	// 定义 父类 和 子类对象
	Parent parent(1);
	Child child(1, 2);

	// 5. 将 Parent 引用 指向 父类对象
	// 结果 - `父类 : x = 1`
	Parent& p2 = parent;
	p2.print();

	// 5. 将 Parent 引用 指向 子类对象
	// 结果 - `父类 : x = 1`
	Parent& p3 = child;
	p3.print();




二、完整代码示例 - 类型兼容性原则与函数重写




1、代码示例


#include "iostream"
using namespace std;

// 父类
class Parent {
public:
	Parent(int a)
	{
		x = a;
		cout << "调用父类构造函数" << endl;
	}

	void print()
	{
		cout << "父类 : x = " << x << endl;
	}
public:
	int x;
};

// 子类
class Child : public Parent {
public:
	// 在子类构造函数初始化列表中 调用 父类构造函数
	Child(int a, int b) : Parent(a)
	{
		y = b;
		cout << "调用子类构造函数" << endl;
	}

	// 子类重写父类的 print 函数
	void print()
	{
		cout << "子类 : x = " << x << " , y = " << y << endl;
	}
public:
	int y;
};

// 父类指针作为函数参数
// 分别传入 子类对象 和 父类对象 地址
void fun(Parent* p)
{
	p->print();
}

// 父类引用作为函数参数
// 分别传入 子类对象 和 父类对象 本身
void fun(Parent& p)
{
	p.print();
}


int main() {

	// 定义父类指针
	Parent* p = NULL;

	// 定义 父类 和 子类对象
	Parent parent(1);
	Child child(1, 2);

	// 1. 调用父类对象的 print 函数
	// 结果 - `父类 : x = 1`
	parent.print();

	// 2. 调用子类对象的 print 函数
	// 结果 - `子类 : x = 1 , y = 2`
	child.print();

	// 3. 将 p 指针指向 父类对象
	// 通过 p 指针 调用指向对象的 print 函数
	// 结果 - `父类 : x = 1`
	p = &parent;
	p->print();

	// 4. 将 p 指针指向 子类对象
	// 通过 p 指针 调用指向对象的 print 函数
	// 结果 - `父类 : x = 1`
	// 虽然将 子类对象 地址赋值给了 p 指针 
	// 但是 调用的 函数仍然是 父类的 print 函数
	// 这是 类型兼容性原则 导致的结果
	p = &child;
	p->print();

	// 5. 将 Parent 引用 指向 父类对象
	// 结果 - `父类 : x = 1`
	Parent& p2 = parent;
	p2.print();

	// 5. 将 Parent 引用 指向 子类对象
	// 结果 - `父类 : x = 1`
	Parent& p3 = child;
	p3.print();

	// 6. 父类指针作为函数参数 
	// 传入父类对象地址 , 结果 - `父类 : x = 1`
	fun(&parent);
	// 传入子类对象地址 , 结果 - `父类 : x = 1`
	fun(&child);

	// 7. 父类引用作为函数参数 
	// 传入父类对象本身 , 结果 - `父类 : x = 1`
	fun(parent);
	// 传入子类对象本身 , 结果 - `父类 : x = 1`
	fun(child);
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

2、执行结果


执行结果 :

调用父类构造函数
调用父类构造函数
调用子类构造函数
父类 : x = 1
子类 : x = 1 , y = 2
父类 : x = 1
父类 : x = 1
父类 : x = 1
父类 : x = 1
父类 : x = 1
父类 : x = 1
父类 : x = 1
父类 : x = 1
请按任意键继续. . .

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/106236.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kafka磁盘写满日志清理操作

最近项目组的kafka集群&#xff0c;老是由于应用端写入kafka topic的消息太多&#xff0c;导致所在的broker节点占满&#xff0c;导致其他的组件接连宕机。 这里和应用端沟通可以删除1天之前的消息来清理磁盘&#xff0c;并且可以调整topic的消息存活时间。 一、调整Topic的消…

【linux】SourceForge 开源软件开发平台和仓库

在linux上面安装服务和工具。我们经常会下载安装包。今天推荐一个网站。 SourceForge 开源软件开发平台和仓库 ​ 全球最大开源软件开发平台和仓库 SourceForge.net&#xff0c;又称SF.net&#xff0c;是开源软件开发者进行开发管理的集中式场所。 SourceForge.net由VA Softwa…

网络安全https

http是明文的&#xff0c;相当于在网上裸奔&#xff0c;引出了https&#xff0c;大多数网站都转为了https&#xff0c;连非法的赌博网站有的都是https的。 1.https的网站是不是必须让用户装数字证书&#xff1f; 答&#xff1a;分两种&#xff0c;一种是单向认证&#xff0c;像…

五、W5100S/W5500+RP2040树莓派Pico<UDP Client数据回环测试>

文章目录 1. 前言2. 协议简介2.1 简述2.2 优点2.3 应用 3. WIZnet以太网芯片4. UDP Client回环测试4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 测试现象 5. 注意事项6. 相关链接 1. 前言 UDP是一种无连接的网络协议&#xff0c;它提供了一种简单的、不可靠的方式来…

KMS在腾讯云的微服务实践助力其降本50%

背景介绍 KMS 是一家日本的游戏公司&#xff0c;主要经营游戏业务、数字漫画业务、广告业务、云解决方案业务等&#xff0c;出品了多款在日本畅销的漫画风游戏&#xff0c;同时有网络漫画专业厂牌&#xff0c;以内容创作为目标&#xff0c;拥有原创 IP 创作、游戏开发等多元化发…

Miniconda、Vscode下载和conda源、pip源设置

1、常用软件下载 1、Miniconda软件下载&#xff1a; windows网址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/?CS&OA 2、最新版Miniconda下载网址&#xff1a;https://docs.conda.io/projects/miniconda/en/latest/ 3、常用代码编辑器VsCode下…

【分享】7-Zip压缩包的密码可以取消吗?

7-Zip压缩包设置了“密码保护”&#xff0c;后面又不想要了&#xff0c;可以取消吗&#xff1f; 首先&#xff0c;我们要分两种情况来看&#xff0c;是记得密码&#xff0c;但不想每次打开压缩包都要输入密码&#xff0c;所以想取消密码&#xff0c;还是把密码忘记了所以想取消…

Linux | 进程地址空间

目录 前言 一、初始进程地址空间 1、实验引入 2、虚拟地址空间 二、什么是进程地址空间 1、基本概念 2、深入理解进程地址空间 3、进程地址空间的本质 4、遗留问题解决 三、为什么要有进程地址空间 1、知识扩展 2、进程地址空间存在意义 3、重新理解挂起 前言 本…

CorelDRAW和AI哪个更好用?

设计软件市场中&#xff0c;CorelDRAW和Adobe Illustrator&#xff08;简称AI&#xff09;无疑是两大重量级选手。它们各自拥有庞大的用户群和丰富的功能&#xff0c;但究竟哪一个更好用&#xff1f;本文将从多个角度出发&#xff0c;对这两款软件进行全面而深入的比较&#xf…

2023 恒创海外服务器双11优惠汇总【附开通流程】

作为香港及亚太数据中心领先服务商恒创科技&#xff0c;最近主推的双11 底价优惠活动中&#xff0c;有一些拥有超高性价比的活动机型放出&#xff0c;引发了一些站长的关注。 为此&#xff0c;小编专门写了本篇服务器选购流程以及活动汇总&#xff0c;希望能够帮助大家更加容易…

Spring Boot整合Spring Fox生成Swagger文档

Spring Fox简介 Springfox是一个用于在Spring应用程序中生成Swagger文档的开源库。它提供了一组注解和工具&#xff0c;可以将你的API代码和文档整合在一起&#xff0c;方便生成和展示API的Swagger文档。 使用Springfox&#xff0c;你可以在Spring Boot项目中集成Swagger&…

原生mysql与mybatis执行update语句的差异

在做一个解除绑定的接口中&#xff0c;发现了这个一个问题&#xff1a; 连续对接口进行测试&#xff0c;发现一直fan返回解除成功&#xff0c;但是逻辑上应该是解除之后&#xff0c;在解除它后就应该回显已解除绑定才对 就一直找原因&#xff0c;sql中使用的是mybatis的…

将安全作为首要目标 — Venus 的现状和前景展望

DeFi 的全面爆发将上一轮牛市推向巅峰。在不断的演化中&#xff0c;DeFi 领域也产生了很多新兴的细分领域&#xff0c;比如收益聚合器、合成资产、各种 DeFi 收益工具&#xff0c;以及最近整个市场都在讨论的 RWA 等。 DeFi 在不断进化&#xff0c;不变的是&#xff0c;DEX 和借…

toluaframework中C#怎么调用Lua的方法以及无GC方法

toluaframework中C#怎么调用Lua的方法 问题Util.CallMethodLuaManager.CallFunctionLuaFunction.LazyCall 解决方案LuaFunction脚本无GC消耗的调用 用法总结 问题 用过luaframework框架的人应该都知道框架提供了Util的工具类&#xff0c;工具类提供了一个方法就是Util.CallMet…

Kubernetes - 一键安装部署 K8S(附:Kubernetes Dashboard)

问题描述 不知道大伙是如何安装 K8s&#xff0c;特别还是集群的时候&#xff0c;我上一次安装搭建的时候&#xff0c;那个恶心到我了&#xff0c;真的是一步一个脚印走完整个搭建流程&#xff0c;爬了不少坑。 于是&#xff0c;才有了今天的文章&#xff0c;到底有没有可以一…

在 Visual Studio Code (VS Code) 中设置

在 Visual Studio Code (VS Code) 中设置代理服务器的详细教程如下&#xff1a; 打开 Visual Studio Code。在顶部菜单栏中&#xff0c;点击 “File”&#xff08;文件&#xff09; > “Preferences”&#xff08;首选项&#xff09; > “Settings”&#xff08;设置&am…

竞赛选题 深度学习人脸表情识别算法 - opencv python 机器视觉

文章目录 0 前言1 技术介绍1.1 技术概括1.2 目前表情识别实现技术 2 实现效果3 深度学习表情识别实现过程3.1 网络架构3.2 数据3.3 实现流程3.4 部分实现代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习人脸表情识别系…

数组的最长递减子序列

求一个数组的最长递减子序列 如{9&#xff0c;4&#xff0c;3&#xff0c;2&#xff0c;5&#xff0c;4&#xff0c;3&#xff0c;2}的最长递减子序列为{9&#xff0c;5&#xff0c;4&#xff0c;3&#xff0c;2} 思路&#xff1a;动态规划 构建与原数组同等容量的辅助数组dp,记…

Lua入门使用与基础语法

文章目录 目的基础说明开发环境基础语法注释数据类型变量流程控制函数 总结 目的 Lua是一种非常小巧的脚本语言&#xff0c;基于C构建并且完全开源&#xff0c;可以方便的嵌入到各种项目中&#xff0c;当然也可以单独使用。Lua经常被用在很多非脚本语言的项目中&#xff0c;用…

目标跟踪ZoomTrack: Target-aware Non-uniform Resizing for Efficient Visual Tracking

论文作者&#xff1a;Yutong Kou,Jin Gao,Bing Li,Gang Wang,Weiming Hu,Yizheng Wang,Liang Li 作者单位&#xff1a;CASIA; University of Chinese Academy of Sciences; ShanghaiTech University; Beijing Institute of Basic Medical Sciences; People AI, Inc 论文链接&…