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

news2024/9/24 1:22:35

文章目录

  • 一、类型兼容性原则与函数重写
    • 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
请按任意键继续. . .

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【鸿蒙软件开发】ArkTS基础组件之Rating(评分组件)、RichText(富文本显示)

文章目录 前言一、Rating组件1.1 子组件1.2 接口参数 1.2 属性1.3 事件1.4 示例代码示例代码1示例代码2 二、RichText富文本显示2.1 子组件2.2 接口参数 2.3 事件2.4 属性2.5 富文本所支持的标签2.6 示例代码 总结 前言 Rating组件&#xff1a;提供在给定范围内选择评分的组件…

基于STM32的汽车仪表系统设计

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、方案设计1.1 总体方案论证1.2 项目总体设计 二、软件设计3.1 主程序设计 三、软件设计3.3 emWin图形界面实现实物附录2 源程序清单 四、 结论五、 文章目录 概要 本次课题基于STM32F407微型控制器以及CAN总线…

智能决策:数字孪生的商业洞察

数字孪生在企业管理中的应用是一项重要的技术趋势&#xff0c;它为企业提供了强大的工具&#xff0c;以数字化的方式模拟和管理其物理资产、流程和运营。本文将探讨数字孪生在企业管理中的关键应用领域&#xff0c;以及它对企业的益处。 1. 制造业优化 数字孪生可以在制造业中…

RabbitMQ-死信交换机和死信队列

1. 简介 DLX: Dead-Letter-Exchange 死信交换器&#xff0c;死信邮箱 2.代码示例 Configuration public class RabbitConfig {final static String exchangeNormalName "exchange.dlx.normal";final static String queueNormalName "queue.dlx.normal"…

springsecurity学习笔记-未完

目录 前言 一、概念 1.什么是springsecurity 2.对比shiro 二、开始项目 1.建立一个空项目&#xff0c;建立module&#xff0c;引入相关依赖 2.启动项目&#xff0c;访问项目 3.自定义密码 总结 前言 记录一下学习springsecurity的过程 开发环境&#xff1a;IDEA 一、概念 1.…

shell脚本的编写(输入、输出、变量、数组等的使用规范及实例)

1.shell中变量的定义 使用变量的值&#xff1a; 例子&#xff1a; 2.外部传参/位置变量 例子&#xff1a; 3.输出---echo 4.输入---read 5.命令置换符 作用:把指令的运行结果赋值给变量 6.数组--shell支持稀疏数组

计算机视觉的相机选型

#你一般什么时候会用到GPT?# 目前市面上的工业相机大多是基于CCD&#xff08;ChargeCoupled Device&#xff09;或CMOS&#xff08;Complementary Metal Oxide Semiconductor&#xff09;芯片的相机。一般CCD制造工艺更加复杂&#xff0c;也会更贵一点&#xff01; 1、CCD工…

请求分页中的内存分配

1.最小物理块数的确定 这里所说的最小物理块数&#xff0c;是指能保证进程正常运行所需的最小物理块数。当系统为进程分配的物理块数少于此值时&#xff0c;进程将无法运行。 2.内存分配策略 1&#xff09;内存分配策略 固定分配是指为每个进程分配一固定页数的内存空间&am…

支持自动生成API文档 Apipost 真香

在数字化时代&#xff0c;API已经成为了应用程序之间进行通信的关键桥梁。随着API的普及和复杂性的增加&#xff0c;API研发和管理也面临着越来越多的挑战。为了更好地应对这些挑战&#xff0c;Apipost提供了一整套API研发工具&#xff0c;包括API设计、API调试、API文档和API自…

碳排放数据,各地区的(直辖市数据细分到区县),含shp和xlsx格式,带符号化

这两天推了道路相关的数据&#xff0c;道路线路、客运飞机场、航空、地铁、火车站点等等交通出行类的数据之前都已发过&#xff0c;需要的可以自己翻一翻。 交通运输行业还比较关注的碳排放数据&#xff0c;也整理出来了&#xff0c;有需要的自取。 数据地址&#xff1a; 全…

政务可视化 玫瑰图和柱折混合图

安装echarts时&#xff0c;需进入到vue-demo的目录下 与第二章操作步骤相同 删除全部默认效果 将上述60像素删除&#xff0c;设置整个背景宽&#xff0c;高等 设置标题 设置图表结构&#xff08;左右两个盒子&#xff09; 设置图表边框&#xff0c;宽&#xff0c;高&#xff0…

Peter算法小课堂—归并排序

位运算 << 这个符号相当于将一个数二进制往左移动几位&#xff0c;如(100110)2<<1(001100)2。相当于乘以2的k次方 >> 这个符号相当于将一个数二进制往右移动几位&#xff0c;如(100110)2<<1(0100110)2。相当于除以2的k次方 归并排序 先看一个视频…

token正确不报错,token失效后却出现报跨域错误

1.今天在使用koajs开发项目时&#xff0c;突然发现前端配置axios的response获取不到后端定义的token失效内容了&#xff0c;取而代之的是出现了跨域的错误。 2. 我马上去查找koajs的跨域中间件配置&#xff0c;发现配置完好cors&#xff0c;token正确时&#xff0c;接口正常访问…

code too large

描述&#xff1a;比较尴尬&#xff0c;一个方法的代码接近10000行了&#xff0c;部署服务器的时候提示(java :code[255,21] too large),提示代码过长&#xff0c;无法运行。 查看了一下百度&#xff1a;解决的思路 JVM规范&#xff1a;「类或接口可以声明的字段数量限制在 655…

水声功率放大器的应用场景是什么

水声功率放大器是一种专门用于水声信号处理和传输的设备&#xff0c;通过放大水声信号的功率&#xff0c;以实现远距离传播和提高信号的清晰度和可辨识度。下面是关于水声功率放大器应用场景的详细解释&#xff1a; 水声通信&#xff1a;水声通信是一种在水下进行声波传输的技术…

电脑如何激活windows

当我们电脑出现如下图&#xff1a; 显示需要激活windows时&#xff0c;操作如下。 1、桌面-新建-文本文档 2、将文档命名为&#xff08;激活windows.bat&#xff09;把原有文档中的后缀.txt去掉 3、点击右键&#xff0c;选择编辑输入代码 slmgr/skms kms.03k.org slmgr/ato4、…

logback-classic包中ThrowableProxy递归缺陷StackOverflowError解析

logback-classic&#xff08;<1.2.12版本&#xff09;ThrowableProxy类中存在递归缺陷&#xff0c;会导致java.lang.StackOverflowError。改缺陷在1.2.12以上版本(包含该版本)中已修复。 如何复现&#xff1a; 两个异常彼此设置casue&#xff1a; 运行后报以下错误 以上写…

Rust 模块系统

文章目录 模块系统crate包cargo 创建库库的使用 模块系统 Rust的{模块系统|the module system}&#xff0c;包括&#xff1a; * 包&#xff08;Packages&#xff09;&#xff1a; Cargo 的一个功能&#xff0c;它允许你构建、测试和分享 crate。 * Crates &#xff1a;一个模…

【Uva】10976-Fractions Again?!

1、题目 2、题意 输入正整数 k k k&#xff0c;找到所有正整数 x ≥ y x \ge y x≥y&#xff0c;使得 1 k 1 x 1 y \frac{1}{k} \frac{1}{x} \frac{1}{y} k1​x1​y1​。 3、分析 既然要求找出所有的 x , y x,y x,y&#xff0c;枚举对象自然是 x , y x,y x,y了。可…

有用过成绩查询系统的老师吗?

是不是有时候觉得手动查询成绩是一件超级繁琐的事情&#xff1f;有了这个成绩查询系统&#xff0c;你就可以告别手动时代啦&#xff01; 先来了解一下什么是成绩查询系统。成绩查询系统是一种可以自动查询学生成绩的系统。通过这个系统&#xff0c;学生可以输入自己的学号或姓名…