c++|多态

c++|多态

  • 1 多态的概念
  • 2 多态的定义及其实现
  • 2.1 满足多态的条件
  • 2.2 虚函数
  • 2.3 虚函数的重写
    • 2.4 析构函数适合加virtural吗
    • 2.4 C++11 override 和 final
    • 2.5 三个概念的对比
  • 3 多态的原理
  • 4 抽象类
    • 4.1 概念
    • 4.2 纯虚函数

1 多态的概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。

2 多态的定义及其实现

```cpp
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
	/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因
	为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议
	这样使用*/
	/*void BuyTicket() { cout << "买票-半价" << endl; }*/
};
void Func(Person& p)
{
	p.BuyTicket();
}
int main()
{

	Person ps;
	Student st;
	Func(ps);
	Func(st);
	return 0;
}

2.1 满足多态的条件

那么在继承中要构成多态还有两个条件:

  1. 必须通过基类的指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

2.2 虚函数

即被virtural修饰的类成员函数

2.3 虚函数的重写

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的
返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
有两个例外

  1. 协变(基类与派生类虚函数返回值类型不同)
    基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。(了解)

  2. 如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,
    都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,
    看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor

协变

class Person {
public:
	virtual A* f() { 
		cout << "Person: " << endl;
			return new A; }
};
class Student : public Person {
public:
	virtual B* f() { 
		cout << "Student:" << endl;;
		return new B; }
};
void Func(Person& p) 
{
	p.f();
}
int main()
{
	Person p;
	Student s;
	Func(p);
	Func(s);
	
	
	return 0;
}

2.4 析构函数适合加virtural吗

class Person {
public:
	~Person() 
	{
		cout << "~Person" << endl;
	}
};

class Student : public Person {
	int* ptr = new int[10];
public:
	~Student() 
	{
		delete ptr;
		cout << "~Student" << endl;
	}
};

int main()
{
	Person * p1 = new Person();
	Person* p2 = new Student();
	// 都调用 Person
	delete p1;
	delete p2;
	return 0;
}

所以我们建议加上 vitural

2.4 C++11 override 和 final

final:修饰虚函数,表示该虚函数不能再被重写

class Car
{
public:
 virtual void Drive() final {}
};
class Benz :public Car
{
public:
 virtual void Drive() {cout << "Benz-舒适" << endl;}
};
  1. override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
class Car{
public:
 virtual void Drive(){}
};
class Benz :public Car {
public:
 virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

2.5 三个概念的对比

在这里插入图片描述

3 多态的原理

class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
	int _i = 1;
};
class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
	int _j = 2;
};
void Func(Person& p)
{
	p.BuyTicket();
}
int main()
{
	Person Mike;
	Func(Mike);
	Student Johnson;
	Func(Johnson);
	return 0;
}

每个有虚函数的对象,都有个一个虚函数表指针,每个虚函数都进入了虚函数表中。
在这里插入图片描述

  1. 观察下图的红色箭头我们看到,p是指向mike对象时,p->BuyTicket在mike的虚表中找到虚
    函数是Person::BuyTicket。
  2. 观察下图的蓝色箭头我们看到,p是指向johnson对象时,p->BuyTicket在johson的虚表中
    找到虚函数是Student::BuyTicket。
  3. 这样就实现出了不同对象去完成同一行为时,展现出不同的形态

满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的。

验证每个虚函数都进入了函数指针表中

class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};
class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
private:
	int b;
};
typedef void  (*VFPTR) () ;
VFPTR p2[10];
void PrintVFT(VFPTR* arr) 
{
	for (int i = 0; i < 4; i++) 
	{
		printf("%p\n", arr[i]);
		VFPTR pf = arr[i];
		(*pf)();
	}
	
}

int main()
{
	Derive d;
	VFPTR* ptr = (VFPTR*)(*(int*)(&d));
	PrintVFT(ptr);
	return 0;
}

4 抽象类

4.1 概念

有纯虚函数的类称为抽象类,抽象类不能实例化。
派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。

4.2 纯虚函数

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。

class Car
{
public:
virtual void Drive() = 0;
};
class Benz :public Car
{
public:
 virtual void Drive()
 {
 cout << "Benz-舒适" << endl;
 }
};
class BMW :public Car
{
public:
 virtual void Drive()
 {
 cout << "BMW-操控" << endl;
 }
};
void Test()
{
Car* pBenz = new Benz;
 pBenz->Drive();
 Car* pBMW = new BMW;
 pBMW->Drive();
}

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

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

相关文章

微信小程序实现容器图片流式布局功能,配合小程序原生框架使用。

小程序实现容器图片流式布局功能&#xff0c;因为目前论坛上也有很多博主出过类似的文章&#xff0c;这里我就以一个小白角度去讲一下如何实现的吧。给作者一点点鼓励&#xff0c;先点个赞赞吧&#x1f44d;&#xff0c;蟹蟹&#xff01;&#xff01; 目标 实现下方效果图 技术…

HarmonyOS鸿蒙应用开发——安装与配置

今天脑子又抽风&#xff0c;前端转完学后端之后&#xff0c;今天大周末早上醒来突然又想学鸿蒙了&#xff0c;刚好有个比赛需要用到鸿蒙&#xff0c;于是乎我就随便点开b站看了一下鸿蒙视频&#xff0c;然后马上来写这篇博客&#xff0c;后续我的鸿蒙的博客可能会跳着、不连续地…

springboot集成达梦数据库8

springboot集成达梦数据库8 官方文档&#xff1a;[https://eco.dameng.com/document/dm/zh-cn/start/java-development.html](https://eco.dameng.com/document/dm/zh-cn/start/java-development.html) 引入maven依赖 <!--添加数据库驱动安装包--> <dependency> …

十六进制转十进制

十六进制转十进制 在玩编程的时候常会碰到十六进制转换的问题。对于专业的大佬大咖这不是问题&#xff0c;小人物总会有些麻烦。我在研究调色板时也遇到进制转换问题。前些时在本站发了十进制转十六进制的博文&#xff0c;今再写十六进制转十进制的转换方法。供大家参考。 下面…

awk编辑器

目录 工作原理 命令格式 普通格式 BEGIN格式 语句循环格式 awk常见的内建变量&#xff08;可直接用&#xff09; 按行打印行内容 统计行数量 按字段输出文本 通过管道、双引号调用 Shell 命令 awk编辑器是一种流编辑器 工作原理 逐行读取文本,默认以空格或tab键为分…

光环P3O不错的一个讲座

光环P3O不错的一个讲座&#xff0c;地址&#xff1a;https://apphfuydjku5721.h5.xiaoeknow.com/v2/course/alive/l_663dc840e4b0694c62c32d1d?app_idapphfuydJkU5721&share_fromu_5c987304d8515_wH2E5HgCgx&share_type5&share_user_idu_5c987304d8515_wH2E5HgCgx…

AIGC-风格迁移-“DEADiff:稳定可控的文本到图像风格化扩散模型 “-CVPR2024

DEADiff: An Efficient Stylization Diffusion Model with Disentangled Representations 代码&#xff1a;https://tianhao-qi.github.io/DEADiff/ 论文&#xff1a;https://arxiv.org/pdf/2403.06951 本文介绍了一种名为DEADiff的方法&#xff0c;旨在解决基于扩散的文本到图…

又翻车了!谷歌急于手动删除搜索中的奇怪AI答案|TodayAI

谷歌公司近日确认&#xff0c;正在“迅速采取行动”删除一些AI工具的奇怪回应。社交媒体上充斥着谷歌新AI概览产品&#xff08;AI Overview&#xff09;说出奇怪话语的例子&#xff0c;从告诉用户在披萨上涂胶水到建议他们吃石头。这次混乱的AI发布导致谷歌不得不手动禁用某些搜…

车灯合面合壳密封使用UV胶的优缺点是什么呢?汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

车灯合面合壳密封使用UV胶的优缺点是什么呢? 车灯合壳密封使用UV胶的优缺点如下&#xff1a; 优点&#xff1a; 快速固化&#xff1a;UV胶通过紫外线照射可以在短时间内迅速固化&#xff0c;大大缩短了车灯制造的工艺流程时间&#xff0c;提高了生产效率。高度透明&#xff…

二叉树——进阶(递归创建,非递归,广度优先,翻转,深度,对称)

二叉树——进阶 二叉树的递归创建非递归前中后序遍历非递归前序遍历非递归中序遍历非递归后序遍历 广度优先遍历二叉树&#xff08;层序遍历&#xff09;翻转二叉树 二叉树深度最大深度最小深度 对称二叉树 二叉树的递归创建 1&#xff0c;二叉树是一种结构相对固定的数据&…

金融信贷风控系统设计模式应用之模版方法

背景介绍 风控系统每种场景 如个人消费贷 都需要跑很多规则 规则1 申请人姓名身份证号实名验证规则2 申请人手机号码实名认证规则3 银行卡预留手机号码实名认证规则4 申请人银行卡预留手机号码在网状态检验规则5 申请人银行借记卡有效性核验规则6 户籍地址与身份证号归属地比…

微信小程序知识点1

一. 页面样式和结构 1.1 小程序组件(html) (1) 区域布局组件 view 定义块级区域&#xff0c;相当于网页中的 div 标签text 定义行内区域&#xff0c;相当于网页中的 span标签 (2) 链接跳转组件 navigator 组件相当于网页中的 a 标签&#xff0c;用来实现页面之间的跳转。 …

基于卷积神经网络的交通标志识别(pytorch,opencv,yolov5)

文章目录 数据集介绍&#xff1a;resnet18模型代码加载数据集&#xff08;Dataset与Dataloader&#xff09;模型训练训练准确率及损失函数&#xff1a;resnet18交通标志分类源码yolov5检测与识别&#xff08;交通标志&#xff09; 本文共包含两部分&#xff0c; 第一部分是用re…

力扣刷题---2206. 将数组划分成相等数对【简单】

题目描述&#x1f357; 给你一个整数数组 nums &#xff0c;它包含 2 * n 个整数。 你需要将 nums 划分成 n 个数对&#xff0c;满足&#xff1a; 每个元素 只属于一个 数对。 同一数对中的元素 相等 。 如果可以将 nums 划分成 n 个数对&#xff0c;请你返回 true &#xf…

高开高走的续作,可不止《庆余年2》

说起最近霸屏的影视剧&#xff0c;莫过于《庆余年2》。火爆全网的讨论度总归是没有辜负观众们五年的等待&#xff0c;在五月的影视市场独占鳌头已成定局。张若昀、陈道明、李沁等一众演员稳定发挥&#xff0c;剧情节奏随着故事发展渐入佳境&#xff0c;评分一路高涨。 对影视作…

【网络安全】社会工程学攻击与防范

一、社会工程学概述 1、社会工程学的定义 通过利用人们的心理弱点、本能反应、好奇心、信任、贪婪等一些心理陷阱进行的诸如欺骗、伤害、信息盗取、利益谋取等对社会及人类带来危害的行为或方法。 当网络恶意攻击者无法通过纯粹的计算机技术达到目的时&#xff0c;高超的情商…

统计信号处理基础 习题解答10-4

题目&#xff1a; 重复习题10.3&#xff0c;但条件PDF变为&#xff1a; 以及均匀先验。如果非常大&#xff0c;这样先验知识很少&#xff0c;则会出现什么情况。 解答&#xff1a; 如果记 那么&#xff0c;根据条件独立性质&#xff0c;得到&#xff1a; 其中&#xff0c;&am…

Web3 游戏平台 Creo Engine 销毁代币总量的20%,以促进长远发展

Creo Engine 5月16日进行了第三次代币销毁&#xff0c;这次的销毁占代币总量的 20%。一共销毁了2亿 $CERO 代币&#xff0c;市场价值接近 2000 万美元。 Creo Engine 致力于连接世界、为玩家提供一站式游戏中心&#xff0c;并提升 Web3 游戏体验。 Creo Engine 发布于2022年&am…

Python学习---基于TCP协议的网络通信程序案例

TCP简介&#xff1a; ●TCP 面向连接、可靠的、基于字节流的传输控制协议 ●TCP的特点 ○面向连接 ○可靠传输 ■应答机制 ■超时重传 ■错误校验 ■流量管控 ●TCP通信模型 TCP严格区分客户…

运维Tips | Linux系统文件命令执行时inode表如何变化?

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路。 ] 大家好&#xff0c;我是【WeiyiGeek/唯一极客】一个正在向全栈工程师(SecDevOps)前进的技术爱好者 作者微信&#xff1a;WeiyiGeeker 公众号/知识星球&#xff1a;全栈工程师修炼指南 主页博…