C++进阶之路---多态(一)

news2024/12/24 20:11:41

46f376db7bb34b068d1fb00b70fa40b7.jpeg

顾得泉:个人主页

个人专栏:《Linux操作系统》 《C++从入门到精通》  《LeedCode刷题》

键盘敲烂,年薪百万!


一、多态的概念

1.概念

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

feedeaf1ad534d4e9c6b3a5782963dc2.png

       举个栗子:比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。

       再举个栗子: 最近为了争夺在线支付市场,支付宝年底经常会做诱人的扫红包-支付-给奖励金的活动。那么大家想想为什么有人扫的红包又大又新鲜8块、10块…,而有人扫的红包都是1毛,5毛…。其实这背后也是一个多态行为。支付宝首先会分析你的账户数据,比如你是新用户、比如你没有经常支付宝支付等等,那么你需要被鼓励使用支付宝,那么就你扫码金额 =random()%99;比如你经常使用支付宝支付或者支付宝账户中常年没钱,那么就不需要太鼓励你去使用支付宝,那么就你扫码金额 = random()%1;总结一下:同样是扫码动作,不同的用户扫得到的不一样的红包,这也是一种多态行为。

       ps:支付宝红包问题纯属瞎编,大家仅供娱乐。


二、多态的定义及实现

1.多态的构成条件

       多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。

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

1.必须通过基类(父类)的指针或者引用调用虚函数
2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写(重写条件:函数名/参数/返回值相同 协变例外)

b1c15fe3bdd949c69f1fae16e0b64b62.png

2.虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。

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

3.虚函数的重写

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

class Student : public Person
{
public:
    virtual void Buyticket()
    {
        cout << "票价--半价" << endl;
    }
    /*void BuyTicket() { cout << "买票-半价" << endl; }*/
};

       虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
       注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用。

void func(Person& p)
{
    p.Buyticket();
}
int main()
{
    Person p;
    Student s;

    func(p);
    func(s);

    return 0;
}

虚函数重写的两个例外:

1.协变(基类与派生类虚函数返回值类型不同)

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

class A{};
class B : public A {};
class Person 
{
public:
     virtual A* f() {return new A;}
};
class Student : public Person 
{
public:
     virtual B* f() {return new B;}
};

2.析构函数的重写(基类与派生类析构函数的名字不同)

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

class Person 
{
public:
     virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person 
{
public:
     virtual ~Student() { cout << "~Student()" << endl; }
};
/*只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。*/
int main()
{
     Person* p1 = new Person;
     Person* p2 = new Student;
     delete p1;
     delete p2;
     return 0;
}

4.C++11 override 和 final

       从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来debug会得不偿失,因此:C++11提供了override和final两个关键字,可以帮助用户检测是否重写。

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

class Car
{
public:
     virtual void Drive() final {}
};
class Benz :public Car
{
public:
     virtual void Drive() {cout << "Benz-舒适" << endl;}
};

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

class Car
{
public:
     virtual void Drive(){}
};
class Benz :public Car 
{
public:
     virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

5.重载、覆盖、隐藏)的对比

3ac61f7477484b54999d000a1b39f35f.png


三、抽象类

1.概念

       在虚函数的后面写上 =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();
}

2.接口继承和实现继承

       普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。


结语:C++关于多态的分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言~~~ 

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

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

相关文章

[gic]-linux和optee的中断处理流程举例(gicv3举例)

目录 环境配置:说明:举例1、当cpu处于REE&#xff0c;来了一个非安全中断2、当cpu处于TEE&#xff0c;来了一个安全中断3、当cpu处于TEE&#xff0c;来了一个非安全中断4、当cpu处于REE&#xff0c;来了一个安全中断答疑 推荐 本文转自 周贺贺&#xff0c;baron&#xff0c;代码…

ROS2从入门到精通0-2:ROS2简介、对比ROS1与详细安装流程

目录 0 专栏介绍1 什么是机器人操作系统&#xff1f;2 ROS的发展历程3 ROS2与ROS1的区别4 ROS2安装4.1 基本安装4.2 测试ROS24.2.1 测试一&#xff1a;发布者与订阅者4.2.2 测试二&#xff1a;海龟仿真器 5 常见问题 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌…

凌鲨开发容器架构

开发容器是基于docker的快速开发搭建方案&#xff0c;在开发容器里面集成了asdf包管理系统和code server ide服务。 这个项目是开源的。 开发容器启动流程 #mermaid-svg-VJYq3izhUZRJA4Eq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fil…

java之mybatis

准备工作 上面4步骤 XML映射文件 动态SQL

git分布式管理-头歌实验冲突处理、忽略文件

一、解决冲突 任务描述 在团队协作开发过程中&#xff0c;可能你和团队中的其他成员&#xff0c;都修改了某个文件的某一部分内容&#xff0c;且其他成员已将该修改推送到了远程仓库。这样当你需要合并他的代码的时候&#xff0c;可能就会在内容上出现冲突&#xff0c;这个时候…

vue之性能优化

1.路由懒加载 所谓路由懒加载&#xff0c;其实就是路由通过import动态引入&#xff0c;而不是在文件最上面一个个全部引入&#xff0c;因为JS执行的时候会优先执行引入的文件&#xff0c;如果一次性引入过多&#xff0c;则会增加处理时长。 2.图片懒加载 图片在网页加载过程…

【CSS】简单的抽屉面板展开收起自然过渡效果的css

目录 效果展示css固定梯形按钮至抽屉面板中间梯形按钮css过渡动画 效果展示 1.收起时点击蓝色梯形按钮展开 2. 展开时点击蓝色按钮收起 3.展开收起时需要过渡自然&#xff0c;有抽屉推拉效果 css 固定梯形按钮至抽屉面板中间 .toggle{ position: absolute;left:-21px;top…

okcc呼叫中心的客服代表应该具备哪些条件?

对每个企业管理者来说&#xff0c;选择最高效和最理想的呼叫中心提供商来简化他们的客户服务操作是一项关键工作内容。除了要确保提供商拥有处理这一重要任务所需的技术和资源之外&#xff0c;确定他们是否具备最高质量的合适人员来执行这项任务同样很重要。 客户服务代表是每…

管理 PostgreSQL 中配置参数的各种方法

管理 PostgreSQL 中配置参数的各种方法 1. 概述 PostgreSQL提供了一个配置文件 postgresql.conf 让用户自定义参数。您可能需要更改一些参数来调整性能或在工作环境中部署 PostgreSQL 服务器。在这篇博文中&#xff0c;我们将探索管理这些参数的不同方法。 2. 以不同方式管理…

mysql的索引、事务、分库分表问题

1.了解MySQL的索引吗&#xff1f;它为什么使用Btree作为底层&#xff0c;而不是其他呢&#xff1f; 这里我们要谈的是其他数据结构的缺点&#xff0c;然后说说Btree的优点&#xff0c;也就看你对MySQL的Btree与其他数据结构熟不熟悉。 Hash &#xff08;1&#xff09;Hash 索引…

Django高级之-缓存

Django高级之-缓存 一 缓存介绍 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作,都会消耗很多的服务端资源,所以必须使用缓存来减轻后端服务…

解决QT cc1plus.exe: error: out of memory allocating

QT中增加资源文件过大时&#xff0c;会编译不过&#xff0c;报错&#xff1a; cc1plus.exe: out of memory allocating 1073745919 bytes 使用qrc资源文件&#xff0c;也就是在QT的工程中添加资源文件&#xff0c;就是添加的资源文件&#xff08;如qrc.cpp&#xff09;会直接被…

MySQl基础入门⑦

上一章知识内容 分析数据且区分数据类型 看下表分析数据的特征&#xff0c;根据其特征确定相应的数据类型。 分析以上表格特征&#xff0c;确定数据类型&#xff0c;并对数据进行分类。分析数据后按固定长度字符串、可变长度字符串、整数、固定精度小数和日期时间数据类型对数…

Find My游戏机|苹果Find My技术与游戏机结合,智能防丢,全球定位

游戏机&#xff0c;又名电子游乐器是使用游戏软件进行玩乐的机器。依照进行游戏的方式的不同&#xff0c;又分为家用游戏机及掌上游戏机。游戏机也可以说是属于电脑的一种&#xff0c;电子游戏机针对影像、音效与操作机能进行特别的强化&#xff0c;也有各种的软件和硬件可供安…

第108讲:Mycat实践指南:枚举分片下的水平分表详解

文章目录 1.枚举分片的概念2.水平分表枚举分片案例2.1.准备测试的表结构2.2.配置Mycat实现枚举分片的水平分表2.2.1.配置Schema配置文件2.2.2.配置Rule分片规则配置文件2.2.3.配置Server配置文件2.2.4.重启Mycat 2.3.写入数据观察水平分表效果 1.枚举分片的概念 枚举分片是根据…

物联网智慧大屏

随着物联网技术的飞速发展&#xff0c;物联网智慧大屏已经成为企业数字化转型的关键组件。那么&#xff0c;什么是物联网智慧大屏&#xff1f;它为企业带来了哪些价值&#xff1f;让我们一起来探索。 一、什么是物联网智慧大屏&#xff1f; 物联网智慧大屏&#xff0c;作为物联…

css flex 布局换行

默认使用display: flex;是不换行的&#xff0c;只需要加上flex-wrap: wrap;就行了&#xff0c;效果图 .app-center {display: flex;flex-wrap: wrap;justify-content:flex-start; } 通过上面我们发现虽然时间换行了&#xff0c;但是每行的边距不一样 加上这个就行了&#xff…

国创证券今日投资参考:金价持续走高 半导体迎新一轮上升周期

上周五&#xff0c;两市股指早盘止跌回升&#xff0c;午后强势上扬&#xff0c;深成指、创业板指、科创50指数盘中均涨超1%&#xff1b;截至收盘&#xff0c;沪指涨0.62%报3046.02点&#xff0c;深成指涨1.1%报9369.05点&#xff0c;创业板指涨0.97%报1807.29点&#xff0c;科创…

【牛客】VL68 同步FIFO

描述 请设计带有空满信号的同步FIFO&#xff0c;FIFO的深度和宽度可配置。双口RAM的参考代码和接口信号已给出&#xff0c;请在答案中添加并例化此部分代码。 电路的接口如下图所示。端口说明如下表。 接口电路图如下&#xff1a; 双口RAM端口说明&#xff1a; 端口名I/O描述…