c++多态(虚函数)机制

news2024/9/22 17:30:51

 c++多态发生的两个条件

c++多态发生的两个条件(牢记):

1、派生类继承含有虚函数的基类,并对基类的虚函数发生重写

2、通过 基类的指针或引用 调用派生类虚函数

多态过程详解

一个案例(黑马)-分析条件一:

//含有虚函数的基类
class Animal
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
	int animal;
};

//含有虚函数的派生类继承基类
//派生类本身有自有的 和基类虚函数同名同参 的虚函数
class Cat:public Animal
{
public:
	virtual void speak()//子类的函数前面不加virtual 也可以重写,但是不规范不建议。
	{
		cout << "小猫在说话" << endl;
	}
	int cat;
};
下面用到的小工具:

使用vs studio 2017的cl命令查看c++类的模型结构-CSDN博客

用工具查看 含有虚函数的基类-结构:

其中有个,虚函数表指针 vfptr(virtual function pointer):

这个指针指向类的虚函数表($vftable),虚函数表中存着该类的所有虚函数的入口地址。如下,假如Aninmal类中再增加两个虚函数,那么虚函数表就如下:

含有虚函数的派生类-结构:

分析派生类结构,Animal的所有成员都继承过来了,包括虚函数指针。

最核心且唯一的改变是:(派生类自己的虚函数指针没了)父类的虚函数指针还在,虚函数指针指向的虚函数表被重写了:

重写更新原则:

1、父子类原来本身都有的虚函数,虚函数表中更新成子类的虚函数入口。【本案例的例子】

2、只有父类才有的虚函数,虚函数表中持有不变。

3、只有子类才有的虚函数,新增到虚函数表里。

关于后面两个案例,可以分别在基类和派生类中添加虚函数印证:

 

二、完整案例-分析条件二

首先了解 “赋值/类型 兼容规则”,这个是语法前提:

        一句话:指在需要基类对象的任何地方,都可以使用public派生类对象来替代(反之不能兼容),当然,也只能访问原基类部分的成员。

举例:

  • 使用 子类对象 为 父类对象 初始化:

        这样基类的对象b中所有数据成员都将具有派生类对象d中对应数据成员的值

Base b; //定义基类base的对象b
Derived d; //定义基类Base的公有派生类Derived的对象d
b=d; //用派生类Derived的对象对基类对象b赋值
  • 使用 父类指针 指向 子类对象:
Derived d; //定义基类Base的公有派生类Derived的对象b
Base *bp=&d; //把派生类对象的地址&d赋值给指向基类的指针bp
			//也就是说使指向基类对象的指针bp也可以指向派生类对象d
  • 将 子类对象 赋给 父类类型的引用:
Base b; //定义基类Base的对象b
Derived d; //定义基类Base的公有派生类Derived的对象d
Base &br=d; //定义基类Base的对象的引用br,并用派生类Derived的对象d对其初始化

        其中后两个,指针和引用的使用,是多态第二个条件的核心组成部分:如果函数的形参是基类对象或基类对象的引用,在调用函数时可以用派生类对象作为实参。

其次了解 指针/引用 调用本质

 “一个pointer或一个reference之所以支持多态,是因为它们并不引发内存任何“与类型有关的内存委托操作; 会受到改变的。只有它们所指向内存的大小和解释方式 而已”

//引用方式调用
void DoSpeak(Animal & animal)
{
	animal.speak();
}

//指针方式调用
void DoSpeak(Animal *animal)
{
	animal.speak();
}

//直接值传递
//这个应该是调用了基类的拷贝构造函数,定义了一个基类对象,因此得到的是一个纯粹的基类。自然不能实现多态
void DoSpeak(Animal animal)
{
	animal.speak();
}

https://blog.csdn.net/shichao1470/article/details/89893508#_2

下面进行 使用过程分析

        下面是前面案例的完整代码,在test01方法中,分别给 DoSpeak 传递了不同派生类型的类对象参数 给 DoSpeak的形参(他们基类的引用)。DoSpeak中对传入的不同类对象做了相同的处理,产生了不同的执行效果。

class Animal
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog :public Animal
{
public:

	void speak()
	{
		cout << "小狗在说话" << endl;
	}

};
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

void DoSpeak(Animal & animal)
{
	animal.speak();
}
//
//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象

void test01()
{
	Cat cat;
	DoSpeak(cat);


	Dog dog;
	DoSpeak(dog);
}


int main() {

	test01();

	system("pause");

	return 0;
}

        至此,不难分析出,为什么要用基类的指针或者引用 调用派生类虚函数? 这样就实现了接口和实现方法的唯一(都按照基类去处理)。实际的处理对象却是不同派生类的基类部分。

        

参考:

C++赋值兼容规则-CSDN博客

【C++】继承 ⑥ ( 类型兼容性原则 | 父类指针 指向 子类对象 | 使用 子类对象 为 父类对象 进行初始化 )-CSDN博客

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

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

相关文章

基于C#实现最长公共子序列

一、作用 最长公共子序列的问题常用于解决字符串的相似度&#xff0c;是一个非常实用的算法&#xff0c;作为码农&#xff0c;此算法是我们的必备基本功。 二、概念 举个例子&#xff0c;cnblogs 这个字符串中子序列有多少个呢&#xff1f;很显然有 27 个&#xff0c;比如其…

IDEA运行 支付宝案例

我 | 在这里 &#x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 &#x1f3e0; 工作 | 广州 ⭐ Java 全栈开发&#xff08;软件工程师&#xff09; &#x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 &#x1f3f7;️ 标签 | 男 自律狂人 目标明确 责任心强 ✈️公…

庖丁解牛:NIO核心概念与机制详解 01 _ 入门篇

文章目录 Pre输入/输出Why NIO流与块的比较通道和缓冲区概述什么是缓冲区&#xff1f;缓冲区类型什么是通道&#xff1f;通道类型 NIO 中的读和写概述Demo : 从文件中读取1. 从FileInputStream中获取Channel2. 创建ByteBuffer缓冲区3. 将数据从Channle读取到Buffer中 Demo : 写…

优思学院|什么是精益生产管理?从一个生活上的故事出发来说明。

你关掉电脑&#xff0c;离开办公室。 一个小时后&#xff0c;你进入家门和孩子们在一起。 你和家人一起吃晚饭。 你的老板打电话来查看你的项目进展。 你哄孩子入睡并给他们读个故事。 作为一个负责任的父母&#xff0c;你想要与孩子们的互动时间增加并提高生活的质量&…

flink 查看写入starrocks的数据量 总行数

针对该connector: https://github.com/StarRocks/docs.zh-cn/blob/main/loading/Flink-connector-starrocks.md

使用 uWSGI 部署 Django 应用详解

概要 部署 Django 应用到生产环境是一个至关重要的步骤&#xff0c;其中选择合适的 WSGI 服务器对于确保应用的稳定性和性能至关重要。uWSGI 是一个流行的选择&#xff0c;它不仅高效、轻量&#xff0c;还非常灵活。本文将详细介绍如何使用 uWSGI 来部署 Django 应用&#xff…

力扣C++学习笔记——C++ assign全面解析

cassign是一个C20标准中新增的头文件&#xff0c;主要提供了assign函数&#xff0c;用于将一个容器内的元素按照特定规则赋值到另一个容器中。它是STL容器操作的重要一环&#xff0c;具有高效、简洁、易用的特点。 assign函数有多个版本&#xff0c;一般使用的是容器类型相同或…

掌握Python中classmethod的妙用,提升代码灵活性与可维护性

概要 在Python编程中&#xff0c;classmethod是一种非常有用的装饰器&#xff0c;它可以将一个方法转换为类方法&#xff0c;使得该方法可以通过类名或实例名直接调用&#xff0c;而不需要传入self参数。通过合理使用classmethod&#xff0c;我们可以提高代码的灵活性、复用性…

基于C#实现字符串相似度

一、概念 对于两个字符串 A 和 B&#xff0c;通过基本的增删改将字符串 A 改成 B&#xff0c;或者将 B 改成 A&#xff0c;在改变的过程中我们使用的最少步骤称之为“编辑距离”。比如如下的字符串&#xff1a;我们通过种种操作&#xff0c;痉挛之后编辑距离为 3&#xff0c;不…

8.6 矢量图层点要素基于规则(Rule-based)渲染使用

文章目录 前言基于规则&#xff08;Rule-based&#xff09;QGis代码实现 总结 前言 前面介绍了矢量-点要素-单一符号、矢量-点要素-分类符号以及矢量-点要素-分级符号的使用本章介绍如何使用基于规则的渲染说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps …

00后如何组织双十一大促看这一篇就够了! | 京东云技术团队

引言 大家好&#xff0c;我是王蒙恩&#xff0c;一名“整顿职场”的00后。作为一名去年刚刚加入京东的校招生&#xff0c;我有幸成为本次CDP平台的11.11备战负责人。虽然早在实习的时候就经历过大促&#xff0c;但是真正组织整个部门的备战还是很难忘的。于是提起笔&#xff0…

二阶段提交

二阶段提交 二阶段提交&#xff08;英语&#xff1a;Two-phase Commit&#xff09;是指&#xff0c;为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法(Algorithm)。 二阶段过程 在两阶段提交过程中&#xff0c;主要分为了两种角色协调者&…

实时监控电脑屏幕的软件丨同时查看12台电脑屏幕

Hello 大家好 又见面啦 今天给大家推荐两款比较实用的监控电脑使用情况、屏幕的软件&#xff01; 软件一 实时性能监控 从软件名就可以看出来&#xff0c;这是一款电脑性能监测工具。它可以实时监测内存、CPU、磁盘占用情况&#xff0c;也能一键结束进程&#xff0c;给电脑提…

MES管理系统与ERP系统的实施顺序与决策

在现今的数字化时代&#xff0c;制造企业纷纷寻求通过先进的系统来提升运营效率。其中&#xff0c;ERP管理系统与MES管理系统被誉为是数字化转型的两大利器。然而&#xff0c;在推进这两个系统时&#xff0c;企业常常面临一个关键问题&#xff1a;究竟应该先实施哪一个系统&…

ASUS华硕ROG幻13笔记本电脑GV301QE原厂Windows10系统

链接&#xff1a;https://pan.baidu.com/s/1aPW0ctRXRNAhE75mzVPdTg?pwdds78 提取码&#xff1a;ds78 华硕玩家国度幻13笔记本电脑锐龙版Ryzen 7 5800HS,显卡3050 3050Ti,3060,3060Ti,3070,3070Ti 原厂W10系统自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办…

Python武器库开发-flask篇之error404(二十七)

flask篇之error404(二十七) 首先&#xff0c;我们先进入模板的界面创建一个404的html页面 cd templates vim 404.html404.html的内容如下&#xff1a; <h1>error!!!</h1>在 Flask 应用程序中&#xff0c;当用户访问一个不存在的页面的时候&#xff0c;会出现 4…

(一)RISC-V 指令集及寄存器介绍

1. RISC-V指令集介绍 RISC-V 念作 “risk-five”&#xff0c;代表着 Berkeley 所研发的第五代精简指令集。 该项目 2010 年始于加州大学伯克利&#xff08;Berkeley&#xff09;分校&#xff0c;希望选择一款 ISA用于科研和教学。经过前期多年的研究和选型&#xff0c;最终决定…

DE算法简介

文章目录 前言一、DE是什么&#xff1f;二、DE流程2.1 初始化种群2.2 变异&#xff08;差分操作&#xff09;2.3 交叉2.4 选择2.5 重复迭代 三、DE运行结果 前言 这两天看了DE算法&#xff0c;简单说下自己的认识 一、DE是什么&#xff1f; 百科定义&#xff1a;差分进化算…

Linux+qt:创建动态库so,以及如何使用(详细步骤)

目录 1、根据安装Qt Creator的向导进行创建 2、开发动态库注意的一些细节 3、给动态库添加一个对外开放的接口文件 4、了解下Qt的 .pri文件&#xff08;非常实用&#xff09; 5、如何调用动态库.so 1、根据安装Qt Creator的向导进行创建 &#xff08;1&#xff09;选择“…

BetterDisplay Pro v2.0.11(显示器颜色校准软件)

BetterDisplay Pro是一款为Mac电脑设计的屏幕亮度调节软件&#xff0c;旨在提高显示器的色彩和亮度表现。它可以根据用户的需求和显示器的特性&#xff0c;自动调整显示器的亮度、色温、对比度等参数&#xff0c;以获得更加真实、舒适的视觉效果。 这款软件拥有智能调节功能&a…