C++中多态的使用和建立条件

一、多态引入

多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。

根据代码,引入多态的概念:

#include <iostream>
using namespace std;//定义一个成人类
class Person {
public:virtual void BuyTicket() { cout << "成人买票-全价" << endl; }
};//定义一个学生类
class Student : public Person {
public:virtual void BuyTicket() { cout << "学生买票-半价" << endl; }
};void Func(Person& p)
{p.BuyTicket();
}
int main()
{Person ps;  //成人对象Student st; //学生Func(ps);  // void Func(Person& p) 参数传参,函数调用Func(st);  // void Func(Person& p) 参数传参,函数调用return 0;
}

在这里插入图片描述
执行结果可以看出根据对象的不同,调用出来不同的结果

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

修改上面的代码,观察结果:
#include <iostream>
using namespace std;class Person {
public://修改前:virtual void BuyTicket() { cout << "成人买票-全价" << endl; }void BuyTicket() { cout << "成人买票-全价" << endl; }
};class Student : public Person {
public://修改前:virtual void BuyTicket() { cout << "学生买票-半价" << endl; }void BuyTicket() { cout << "学生买票-半价" << endl; }
};void Func(Person& p)
{p.BuyTicket();
}
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
}

在这里插入图片描述
我们去掉virtual 关键字之后,看到结果都是调用父类的BuyTicket()函数。 原因分析:student类继承person类,两个类里面的BuyTicket()函数函数名一样,构成重定义(1.函数名相同 2.两个函数分别在父子类的作用域里 3. 父子类的同名函数不构成重写),所以子类对象赋值给父类对象的时候,会将子类对象中的父类切出来,自然而然调用的是父类的成员函数

我们再修改代码,思考结果:
#include <iostream>
using namespace std;class Person {
public:virtual void BuyTicket() { cout << "成人买票-全价" << endl; }
};class Student : public Person {
public:virtual void BuyTicket() { cout << "学生买票-半价" << endl; }
};void Func(Person p)  //修改前:Person& p
{p.BuyTicket();
}
int main()
{Person ps;Student st;Func(ps);Func(st);return 0;
}

在这里插入图片描述
这个结果的产生原因和上面的原因是一致的,父类赋值给父类对象自然调用父类的成员函数、子类对象赋值给父类对象造成“切片”,将子类中的父类那一部分切出去,让父类对象调用

再修改代码,看结果:
#include <iostream>
using namespace std;class Person {
public:virtual void BuyTicket() { cout << "成人买票-全价" << endl; }
};class Student : public Person {
public:virtual void BuyTicket() { cout << "学生买票-半价" << endl; }
};void Func(Person* p)  //修改前:Person& p
{p->BuyTicket();
}
int main()
{Person ps;Student st;Func(&ps);  //修改前 Func(ps);Func(&st);  //修改前 Func(st);return 0;
}

在这里插入图片描述

使用指针的时候又根据指向对象的不同,调用出不同的结果

根据上面的代码结果,我们可以大概感知到多态就是根据不同继承关系的类对象,调用同一函数时产生了不同的行为。那么产生多态的条件是什么呢?


文章目录

  • 一、多态引入
        • 修改上面的代码,观察结果:
        • 我们再修改代码,思考结果:
        • 再修改代码,看结果:
  • 二、多态构成的条件
        • 回顾上面的代码,感受多态的条件
        • 析构函数的重写-析构函数名统一会被处理成destructor()
        • C++11 新语法:override 和 final
        • 抽象类
            • 1、概念
            • 2、 抽象类代码感知
  • 总结


二、多态构成的条件

重写的概念

  • 两个函数分别在子类和父类的作用域中
  • 函数名 / 返回值 / 参数都必须相同
  • 两个函数必须是虚函数 (被virtual 修饰的类成员函数成为虚函数
  • 注意:参数只看类型是否相同,不看缺省值

多态构成的条件

  • 需要在继承中使用
  • 必须使用父类的引用或者指针调用虚函数
  • 被调用的函数必须是虚函数,且子类必须对父类的虚函数进行重写
回顾上面的代码,感受多态的条件
#include <iostream>
using namespace std;
class Person {
public://父类的虚函数virtual void BuyTicket() { cout << "成人买票-全价" << endl; }
};class Student : public Person {
public://子类 重写 父类的虚函数(重写:函数名、返回值、参数必须相同)virtual void BuyTicket() { cout << "学生买票-半价" << endl; }
};void Func(Person* p)
{p->BuyTicket();
}
int main()
{Person ps;Student st;Func(&ps);Func(&st);return 0;
}

这时候指针p,它指向什么类型,就调用该类型的对象里面的成员

在这里插入图片描述

析构函数的重写-析构函数名统一会被处理成destructor()

只有子类 Student 的析构函数重写了 Person 的析构函数,下面的 delete 对象调用析构函
数,才能构成多态,才能保证 p1 和 p2 指向的对象正确的调用析构函数。
函数名处理成destructor() 才能满足多态:
如果父类的析构函数为虚函数,此时子类析构函数只要定义,无论是否加virtual关键字,
都与父类的析构函数构成重写,虽然父类与子类析构函数名字不同。虽然函数名不相同,
看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处
理,编译后析构函数的名称统一处理成destructor。

class Person {
public:virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person {
public:virtual ~Student() { cout << "~Student()" << endl; }
};
int main()
{Person* p1 = new Person;Person* p2 = new Student;delete p1;delete p2;return 0; 
}

在这里插入图片描述
所以当父类的指针指向子类的对象时,一定需要将父类的析构函数写成虚函数,如果不定义成虚函数,那么delete p的时候,就会只父类的析构函数(切片),不会调用子类的析构函数,造成内存泄漏

C++11 新语法:override 和 final

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

在这里插入图片描述

override: 检查子类虚函数是否重写了父类某个虚函数,如果没有重写编译报错

在这里插入图片描述

抽象类
1、概念

在虚函数的后面写上 “= 0” ,则这个函数为纯虚函数包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象子类继承后也不能实例化出对象,只有重写纯虚函数,子类才能实例化出对象。纯虚函数规范了子类必须重写,另外纯虚函数更体现出了接口继承。
在这里插入图片描述

2、 抽象类代码感知
#include <iostream>
using namespace std;class Car
{
public:virtual void Drive() = 0;//	// 实现没有价值,因为没有对象会调用他//	/*virtual void Drive() = 0//	{//		cout << " Drive()" << endl;//	}*/
};
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();
}
int main()
{Test();return 0;
}

在这里插入图片描述


总结

今天我们熟悉了多态的构成条件以及多态的使用,下一次我们详细聊聊多态的原理,感知一下为什么会出现这样的结果?编译器是怎么做得?

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

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

相关文章

【计算机毕设选题推荐】图书在线商城SpringBoot+SSM+Vue

前言&#xff1a;我是IT源码社&#xff0c;从事计算机开发行业数年&#xff0c;专注Java领域&#xff0c;专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 项目名 基于SpringBoot的图书在线商城 技术栈 SpringBootVueMySQLMaven 文章目录 一、图书在线商城…

[ Windows ] ping IP + Port 测试 ip 和 端口是否通畅

开发过程中经常会黑窗口中手动测试一下计划请求的目标ip和端口是否通畅&#xff0c;测试方式如下&#xff1a; 一、单纯测试ip是否能够 ping 通&#xff0c;这个比较熟悉了&#xff0c;运行 cmd 打开黑窗口 输入如下指令&#xff0c;能够如下提示信息&#xff0c;表示端口是通…

Cloud Studio连接MySQL,Access denied for一系列问题

官方文档有写如何安装Mysql $ apt update $ apt install mysql-server mysql-client -y$ service mysql start mysql -uroot -p123456进入MySQL命令行 问题出在连接数据库这一步&#xff0c;命令行能进去&#xff0c;但是数据库插件和代码都连不上 Access denied for 大概率…

35 机器学习(三):混淆矩阵|朴素贝叶斯|决策树|随机森林

文章目录 分类模型的评估混淆矩阵精确率和召回率 接口介绍其他的补充 朴素贝叶斯基础原理介绍拉普拉斯平滑下面给出应用的例子朴素贝叶斯的思辨 决策树基础使用基本原理信息熵信息增益信息增益率Gini指数 剪枝api介绍 随机森林------集成学习初识基本使用api介绍 分类模型的评估…

音频录制和处理软件 Audio Hijack mac中文版说明

Audio Hijack mac是一款功能强大的音频录制和处理软件&#xff0c;它可以帮助用户从各种来源捕获和处理音频。 首先&#xff0c;Audio Hijack具有灵活的音频捕获功能。它支持从多个来源录制音频&#xff0c;包括麦克风、应用程序、网络流媒体、硬件设备等等。你可以选择捕获整个…

告别传统纸质期刊,电子期刊更环保更快捷

​【新发现】随着科技的发展&#xff0c;电子期刊逐渐取代了传统的纸质期刊&#xff0c;成为人们获取信息的新选择。电子期刊不仅环保&#xff0c;而且快捷方便&#xff0c;但是你知道怎么制作电子期刊吗&#xff1f; 不会制作的可以试试我推荐的这个网站----FLBOOK电子杂志制作…

Android Activity 启动时获取View的宽高为0?正确获取View宽高的方式

一、描述 假设你在 Activity 的 onCreate() 方法或 onResume() 方法去获取 View 的宽高信息&#xff0c;会发现拿到的宽高大概率都是0。这是由于 View 很可能还未完成布局&#xff0c;而没有宽高信息。 二、解决 1. 判断 View 是否已经完成绘制 使用 View 类的 isLaidOut()…

无代码玩转web UI自动化

可以直接进入官网下载开源版或点击右上角体验企业版体验 RunnerGo UI自动化平台 RunnerGo提供从API管理到API性能再到可视化的API自动化、UI自动化测试功能模块&#xff0c;覆盖了整个产品测试周期。 RunnerGo UI自动化基于Selenium浏览器自动化方案构建&#xff0c;内嵌高度…

报错:AttributeError: module ‘tensorflow‘ has no attribute ‘flags‘

改成如下&#xff1a; 报错原因&#xff1a;tensorflow1.x与2.x版本问题不兼容

Pyttsx3+Windows语音合成不同的声音

""" # ******************************************************************************** # python如何实现文字转语音,并且解决发声生硬的问题。 # ********************************************************************************** "…

算法必刷系列之查找、排序

文章目录 二分查找顺序查找二分查找迭代写法二分查找递归写法元素中有重复元素的二分查找在排序数组中查找元素的第一个和最后一个位置山脉数组的峰顶索引旋转数字的最小数字找缺失数字优化求平方根二叉搜索树中搜索指定值验证二叉搜索树有序数组转化为二叉搜索树 快速排序以第…

vue el-dialog封装成子组件(组件化)

前言 实际开发过程中我们经常听见组件化开发&#xff0c;但在实际开发过程中&#xff08;没有人审查时&#xff09;怎么方便来 我们有时是因为时间不够&#xff0c;所以把所有代码写在一个页面。当业务逻辑复杂时可能会有1k多行 虽然不能要求自己写出高效复用性高的组件&…

今日最新版早安问候大全,秋天早上好祝福短句,生活顺心,一切开心

天上最美的是星星&#xff0c;关心朋友的是短信&#xff0c;人间最美的是真情&#xff0c;外表留给人的是印象&#xff0c;内心留给人的是感情&#xff0c;珍惜了今天你就拥有了明天&#xff0c;愿你开怀地笑&#xff0c;温柔地睡&#xff01;早安朋友&#xff01; 早晨的阳光…

Leetcode——数组的旋转

189. 轮转数组 class Solution { public:void rotate(vector<int>& nums, int k) {int lennums.size();vector<int> num(len);for(int i0;i<len;i){num[(ik)%len]nums[i];}nums.assign(num.begin(),num.end());} };旋转数组 没看出数学公式gg 正确答案 cl…

JNI查漏补缺(2)JNI动态注册

目录 一、JNI动态注册是什么&#xff1f; 二、JNI动态注册使用步骤 1.新增gMethods数组和JNI_OnLoad函数 2.完整HelloWorld.cpp 3.运行测试 总结 一、JNI动态注册是什么&#xff1f; 静态注册的情况下&#xff0c;java调用的接口和jni层实现的接口有强制的一一对应关系&a…

AI大模型高速发展,Web3还远吗?

在过去的几年里&#xff0c;人工智能&#xff08;AI&#xff09;和Web3技术都经历了令人瞩目的发展。AI大模型&#xff0c;特别是像GPT-3、GPT-4等这样的巨型语言模型&#xff0c;已经成为AI领域的明星&#xff0c;而Web3则代表了下一代互联网的愿景&#xff0c;具有去中心化和…

最近邻插值的原理及实现

1. 介绍 插值算法一般用来做上采样和下采样,最邻近插值算法,是插值算法中最简单的一种。 最邻近插值:将每个目标像素找到距离它最近的原图像素点,然后将该像素的值直接赋值给目标像素。 优点: 实现简单,计算速度快 缺点:插值结果缺乏连续性,可能会产生锯齿状的边缘,对…

scratch时间游戏 2023年9月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch时间游戏 一、题目要求 1、准备工作 2、功能实现 二、案例分析

Cocos Creator3.8 项目实战(十)使用 protobuf详细教程

在 Cocos Creator 中使用 protobuf.js 库可以方便地进行协议的序列化和反序列化。 下面是使用 protobuf.js 的详细说明&#xff1a; 一、protobuf环境安装 1、安装 npm protobuf环境安装安装需要使用 npm 命令进行&#xff0c;因此首先需要安装 npm 。 如果你还没安装 npm …

【面试题】2023虹软计算机视觉一面

来源&#xff1a;投稿 作者&#xff1a;LSC 编辑&#xff1a;学姐 1.自我介绍 2.介绍了自己的项目&#xff0c;并提问项目&#xff0c;讲了30分钟 3.介绍centernet&#xff0c;它和其他目标检测模型有什么区别 4.介绍yolov5 5.介绍focal loss 6.双线性插值和最近邻插值的区…