C++从零开始的打怪升级之路(day43)

这是关于一个普通双非本科大一学生的C++的学习记录贴

在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料

那么开启正题

今天分享的是关于多态的知识点

1.多态的概念及定义,实现

1.1概念

通俗来说,就是多种形态,具体来说就是不同对象去完成某种行为,会产生不同的状态

比如,买票这个行为,普通人买票是全价买票,残疾人买票是半价买票,军人买票是优先买票

1.2定义及实现

1.2.1多态的构成条件

多态是不同继承关系的类对象,去调用同一函数

多态条件:

1.必须通过基类的指针或者引用调用虚函数

2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写(覆盖)

1.2.2虚函数

virtual修饰的类成员函数称之为虚函数

class Person
{
public:virtual void Buy(){cout << "Person::买票-全价" << endl;}
};

1.2.3虚函数的重写

虚函数的重写(覆盖):派生类中有一个跟基类完全相同(返回类型,函数名字,参数列表)的虚函数,称派生类的虚函数重写了基类的虚函数

class Person
{
public:virtual void Buy(){cout << "Person::买票-全价" << endl;}
};class Student : public Person
{
public:virtual void Buy(){cout << "Student::买票-半价" << endl;}
};void Func(Person& p)
{p.Buy();
}int main()
{Person p;Student s;Func(p);Func(s);return 0;
}

虚函数重写的两个例外

1.协变

基类与派生类返回类型不一样,基类虚函数返回基类对象的指针或引用,派生类对象虚函数返回派生类对象的指针或引用

2.析构函数的重写

我们来看下面的代码

class A
{
public://virtual ~A()~A(){cout << "~A()" << endl;}
};class B : public A
{
public://virtual ~B()~B(){cout << "~B()" << endl;}
};void Test1()
{A* p1 = new A;A* p2 = new B;delete p1;delete p2;
}

当我们不将析构函数写为虚函数时,就可能导致B(派生类)析构函数未调用,可能导致内存泄漏,写成虚函数后可以正常使用

但是明明他们的函数名不同,为什么能重写呢,我们来看下面

编译器其实对析构函数名称做了特殊处理,编译后统一处理成destructor,这样就符合了多态的条件

2.C++11里的override和final关键字

经过上面的学习我们可以发现,C++对函数重写的要求很严格,而在实际运用当中,我们有时候会出现一些低级小错误,比如拼写错误,而这种错误是无法检查出来的,故有了以下关键字的出现

1.override:检查派生类虚函数是否重写了某个函数,如果没有进行重写编译报错

class A
{
public:virtual void Print(){cout << "~A()" << endl;}
};class B : public A
{
public:virtual void Pirnt() override{cout << "~B()" << endl;}
};

2.final:修饰虚函数,表示虚函数不能被重写(在类后面加上表示类不能被继承)

class A
{
public:virtual void Print() final{cout << "~A()" << endl;}
};class B : public A
{
public:virtual void Print(){cout << "~B()" << endl;}
};

3.重载,重写(覆盖),重定义(隐藏)的对比

重载:两个函数在同一作用域,函数名相同,参数列表不同

重写:两个函数分别在基类和派生类,函数名 / 参数列表 / 返回值 相同(协变除外),两个函数必须是虚函数

重定义:两个函数分别在基类和派生类,函数名相同,不构成重写

4.抽象类

在虚函数后面加上 = 0,则这个函数为纯虚函数,包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象,派生类继承后也无法实例化出对象,只有重写虚函数,派生类才能实例化出对象,纯虚函数规范了派生类必须重写,另外也体现出了接口继承

{
public:virtual void Print() = 0;
};class B : public A
{
public:void Print(){cout << " hehe" << endl;}
};void Test()
{// A a;B b;
}

上面提到了接口继承,与此对应的还有实现继承,普通函数是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生列继承的是基类虚函数的接口,目得是为了重写,达成多态,所以如果不是实现多态,不要把函数定义为虚函数

5.多态的原理

5.1虚函数表

class A
{
public:virtual void Print(){}int _a;
};void Test()
{cout << sizeof(A) << endl;
}

(32位环境下)运行以上代码可以发现输出结果不是4而是8,我们再通过调试监视窗口又可以发现除了_a成员,还有一个_vfptr放在对象的前面(vs环境下),对象的这个指针叫做虚函数表指针,每一个含有虚函数的类中都至少有一个虚函数表指针,虚函数的地址存在虚函数中

class A
{
public:virtual void Print(){cout << "A" << endl;}int _a;
};class B : public A
{
public:virtual void Print(){cout << "B" << endl;}int _b;
};

通过以上代码和测试我们可以发现

1.派生类对象也有一个虚表指针,但是和基类的不相同,它里面的虚函数如果完成了重写将会存派生类的虚函数,因此虚函数的重写也叫做覆盖

2.虚函数表本质是一个指针数组,一般情况下,这个数组最后放了一个nullptr

3.虚表存的是虚函数指针,不是虚函数,虚函数存在于代码段(常量区)

5.2多态的原理

不同对象调用函数引发多态的原因就是本质就是调用了不同的虚函数,函数调用时,通过_vfptr找到该对象的虚表,再到虚表中找到该调用的虚函数

可以看出,多态的函数调用,不是在编译时确定的,而是在运行后到对象中找到的,不满足多态的普通函数是在编译时就确定好的

这里注意,内联函数因为没有函数地址,所以是无法构成多态的

5.3动态绑定和静态绑定

1.静态绑定又叫做前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态,比如:函数重载

2.动态绑定又叫做后期绑定(晚绑定),在程序运行期间,具体拿到的确定程序的具体行为,调用具体函数,也称为动态多态

新手写博客,有不对的位置希望大佬们能够指出,也谢谢大家能看到这里,让我们一起学习进步吧!

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

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

相关文章

[Python] 添加重试机制来处理某些可能出现异常的函数

在 Python 中&#xff0c;如果你想要添加重试机制来处理某些可能出现异常的函数&#xff0c;可以使用 retry 装饰器。虽然 Python 标准库中没有提供内置的 retry 装饰器&#xff0c;但你可以使用第三方库 tenacity 来实现这个功能。 tenacity 是一个流行的 Python 库&#xff…

Ubuntu18.04运行ORB-SLAM3

ORB-SLAM3复现(ubuntu18) 文章目录 ORB-SLAM3复现(ubuntu18)1 坐标系与外参Intrinsic parameters2 内参Intrinsic parameters2.1 相机内参① 针孔模型Pinhole② KannalaBrandt8模型③ Rectified相机 2.2 IMU内参 3 VI标定—外参3.1 Visual calibration3.2 Inertial calibration…

STM32类别概述、下载程序及启动过程分析

STM32类别概述、下载程序及启动过程分析 STM32类别STM32下载程序STM32启动过程分析 STM32类别 STM32 目前总共有 5 大类&#xff0c;18 个系列 结合 STM32F1 的芯片来说&#xff0c;其 CMSIS 应用程序的简单结构框图&#xff0c;不包括实时操作系统和 中间设备等组件&#xf…

find函数-秒了道题

秒了 笑死 还是规规矩矩做吧 string类的find()函数用于在字符串中查找字符或子串&#xff0c;返回第一个匹配的位置。 class Solution { public:int strStr(string haystack, string needle) {return haystack.find(needle);} };

搜维尔科技:Manus Prime X系列手套介绍,由 PrimeXMarkerMocap 和Prime X Haptic VR 手套组成

搜维尔科技&#xff1a;Manus Prime X系列手套介绍&#xff0c;由 PrimeXMarkerMocap 和Prime X Haptic VR 手套组成 Manus Prime X&#xff08;点击进入官网&#xff09;系列手套介绍&#xff0c;由 PrimeXMarkerMocap 和Prime X Haptic VR 手套组成

深入理解操作系统Operator System(1)

目录 OS概念 设计OS的目的 OS定位 操作系统对下的结构层次示意图 理解操作系统的"管理"❗❗ "管理"被管理者的数据 怎么获取被管理者的数据 获取被管理者什么"数据" 数据过多&先描述再组织❗ C/C中的体现 解释OS对硬件的"管…

RabbitMQ(控制台模拟收发消息与数据隔离)

1.RabbitMQ架构图 publisher&#xff1a;生产者&#xff0c;也就是发送消息的一方 consumer&#xff1a;消费者&#xff0c;也就是消费消息的一方 queue&#xff1a;队列&#xff0c;存储消息。生产者投递的消息会暂存在消息队列中&#xff0c;等待消费者处理 exchange&…

获取数据库最新的一条打卡时间数据SQL语句

获取数据库最新的一条打卡时间数据SQL语句 上班表创建SQL语句 CREATE TABLE "PunchIn" ("id" INT NOT NULL,"emp_code" VARCHAR(50) NOT NULL COLLATE Chinese_PRC_CI_AS,"punch_in_time" DATETIME NOT NULL,"status" VAR…

Java 抽象类与方法:实现安全性与代码重用

Java 内部类 简介 在 Java 中&#xff0c;可以嵌套类&#xff08;即类内部的类&#xff09;&#xff0c;称为内部类。嵌套类的目的是将属于一起的类分组&#xff0c;从而使您的代码更可读和可维护。 访问内部类 要访问内部类&#xff0c;请创建外部类的对象&#xff0c;然后…

c语言-函数-009

2.函数传参: 2.1赋值传递&#xff08;复制传递&#xff09;函数体内部想要使用函数体外部变量值的时候使用复制传递2.2全局变量传递#include <stdio.h>int Num1 100; int Num2 200; int Ret 0;void Add(void) {Ret Num1 Num2;return; }int main(void) {Add();printf…

深度解析速卖通商品详情API:Python实战与高级技术探讨

速卖通商品详情API接口实战&#xff1a;Python代码示例 一、准备工作 在开始之前&#xff0c;请确保你已经完成了以下步骤&#xff1a; 在速卖通开放平台注册账号并创建应用&#xff0c;获取API密钥。阅读速卖通商品详情API接口的文档&#xff0c;了解接口的使用方法和参数要…

什么是物联网?物联网如何工作?

物联网到底是什么&#xff1f; 物联网(Internet of Things&#xff0c;IoT)的概念最早于1999年被提出&#xff0c;官方解释为“万物相连的互联网”&#xff0c;是在互联网基础上延伸和扩展&#xff0c;将各种信息传感设备与网络结合起来而形成的一个巨大网络&#xff0c;可以实…

[SpringCloud] OpenFeign核心架构原理 (一)

Feign的本质: 动态代理 七大核心组件 Feign底层是基于JDK动态代理来的, Feign.builder()最终构造的是一个代理对象, Feign在构建对象的时候会解析方法上的注解和参数, 获取Http请求需要用到基本参数以及和这些参数和方法参数的对应关系。然后发送Http请求, 获取响应, 再根据响…

Python Web开发记录 Day6:MySQL(关系型数据库)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 六、MySQL1、MySQL-概述和引入①MySQL是什么&am…

liunx安装jdk、redis、nginx

jdk安装 下载jdk,解压。 sudo tar -zxvf /usr/local/jdk-8u321-linux-x64.tar.gz -C /usr/local/ 在/etc/profile文件中的&#xff0c;我们只需要编辑一下&#xff0c;在文件的最后加上java变量的有关配置&#xff08;其他内容不要动&#xff09;。 export JAVA_HOME/usr/l…

docker部署aria2-pro

前言 我平时有一些下载视频和一些资源文件的需求&#xff0c;有时候需要离线下载&#xff0c;也要速度比较快的方式 之前我是用家里的玩客云绝育之后不再写盘当下载机用的&#xff0c;但是限制很多 我发现了aria2 这个下载器非常适合我&#xff0c;而有个大佬又在原来的基础…

10 OpenCV 形态学的应用

文章目录 算子形态学提取直线示例 算子 adaptiveThreshold 二值化算子 adaptiveThreshold(src, dstNone,maxValue, adaptiveMethod, thresholdType, blockSize, C, ) /* *src&#xff1a;灰度化的图片 *dst&#xff1a;输出图像&#xff0c;可选 *maxValue&#xff1a;满足条件…

关于程序员如何选择职业赛道

程序员作为一个独具特色的职业群体&#xff0c;面临着诸多挑战和机遇。在选择职业赛道方面&#xff0c;程序员需要考虑自身兴趣、技能、发展前景等因素&#xff0c;以便找到最适合自己的发展路径。本文将从不同角度探讨程序员如何选择职业赛道。 首先&#xff0c;程序员应该认…

C#中对象的相等性与同一性的判断方法总结

C#对象的相等性与同一性 1. 概述与准备1.1 概述1.2 准备 2. Equals(Object)2.1 功能&#xff1a;2.2 实例&#xff1a;2.3 扩展&#xff1a;2.4 重写此方法 3. Equals(Object, Object)3.1 功能3.2 实例 4. ReferenceEquals(Object, Object)4.1 功能4.2 使用场景&#xff1a;4.3…

人工智能+

上上一个风口是互联网&#xff0c;信息分享。 上一个风口是物联网&#xff0c;实现万物互联。 如今再提人工智能&#xff0c;传感器大数据AI算法&#xff0c;尽量地减少人为干预&#xff0c;替代人工作或实现人无法执行的工作。 弱人工智能 所谓弱人工智能就是仅在单个领域…