【C++干货铺】继承后的多态 | 抽象类

=========================================================================

个人主页点击直达:小白不是程序媛

C++系列专栏:C++干货铺

代码仓库:Gitee

=========================================================================

目录

多态的概念

多态的定义和实现

多态的定义条件

虚函数

虚函数的重写

特殊情况

协变(基类和派生类的虚函数返回值不同)

析构函数的重写

C++11 override 和 final关键字

重载、重写(覆盖)、重定义(隐藏)的对比

抽象类


多态的概念

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

举个栗子:很多朋友在外地上大学,回家或者去学校可能都会买火车票或者其他交通工具的票。但是作为一个大学生我们是有学生认证的大学生身份,买票有打折优惠;但是对于其他不是学生的公民来说就是普通人的身份是享受不到这个优惠的,必须全价买票;又或者对于军人来说,他们有军人的身份,军人优先买票。

因此对于买票这个行为,当普通人买票时,是全价买票学生买票时,是半价买票军人
买票
时,是优先买票


多态的定义和实现

多态的定义条件

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

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

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

虚函数

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

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

虚函数的重写

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

注意:重写只是对函数体的内容重写而不是对整个函数重写,使用的还是基类的接口,只不过是函数体的内容变了。

class Person
{
public :virtual void Buy(){cout << "普通人——全价买票" << endl;}
};
class Student :public Person
{
public:virtual void Buy(){cout << "学生——半价买票" << endl;}
};
void Func(Person& p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
}

特殊情况

在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用。

class Person
{
public :virtual void Buy(){cout << "普通人——全价买票" << endl;}
};
class Student :public Person
{
public:virtual void Buy(){cout << "学生——半价票" << endl;}//派生类的虚函数前面可以不加virtual 但是这样并不规范,不建议这样使用//void Buy()//{//	cout << "学生——半价票" << endl;//}
};
void Func(Person& p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
}

虚函数的两个例外:

协变(基类和派生类的虚函数返回值不同)

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

class Person
{
public:virtual Person* Buy(){cout << "普通人——全价买票" << endl;return nullptr;}
};
class Student :public Person
{
public:virtual Student* Buy(){cout << "学生——半价票" << endl;return nullptr;}
};
void Func(Person& p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
}

返回值可以为其他类的指针

class A
{
public:
};
class B : public A
{
public:
};
class Person
{
public:virtual A* Buy(){cout << "普通人——全价买票" << endl;return nullptr;}
};
class Student :public Person
{
public:virtual B* Buy(){cout << "学生——半价票" << endl;return nullptr;}
};
void Func(Person& p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
}

析构函数的重写

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

class Person
{
public :virtual ~Person(){cout << "~Person()" << endl;}
};
class Student
{
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;
}

C++11 override 和 final关键字

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

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

class Person
{
public :virtual void Func()final{cout << "被final修饰" << endl;}
};
class Student : public Person
{
public:virtual void Func(){}
};

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

//override
// 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
class Person
{
public:virtual void Func() {};
};
class Student : public Person
{
public:void Func ()override {};
};

重载、重写(覆盖)、重定义(隐藏)的对比


抽象类

抽象类的概念

虚函数的后面写上 =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;}
};
int main()
{Benz b;b.Drive();BMW m;m.Drive();return 0;
}


今天对继承之后的多态的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法。您三连的支持就是我前进的动力,感谢大家的支持!! !

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

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

相关文章

深度学习中的预测图片中的矩形框、标签、置信度分别是什么意思。

问题描述&#xff1a;深度学习中的预测图片中的矩形框、标签、置信度分别是什么意思。 问题解答&#xff1a; 目标框&#xff08;Bounding Box&#xff09;&#xff1a; 描述目标位置的矩形边界框。 类别标签&#xff1a; 表示模型认为目标属于哪个类别&#xff08;例如&#…

【Java JVM】实例对象内存布局

当 Java 应用启动后, 基本就是在不断的创建对象, 回收对象的过程中。 而这些创建的对象基本都是存放在应用的堆 (heap) 中, 但是这些对象在堆中又是什么样子的呢? 在这篇文章中, 我们分析一下 Java JVM 中实例对象的内存布局。 在 HotSpot 虚拟机里, 对象在堆内存中的存储布局…

MySQL_12.Innodb存储引擎参数

1启动Innodb存储引擎 show variables like %default_storage_engine%; 在my.cnf文件加入 default_storage_engineinnodb ,重启mysql生效 2.Innodb初期重要的参数设置 show variables like %innodb%; 列举innodb重要参数: (1)innodb_buffer_pool_size 类似Oracle的SGA 用于…

SpringBoot+OCR 实现PDF 内容识别

一、SpringBootOCR对pdf文件内容识别提取 1、在 Spring Boot 中&#xff0c;您可以结合 OCR&#xff08;Optical Character Recognition&#xff09;库来实现对 PDF 文件内容的识别和提取。 一种常用的 OCR 库是 Tesseract&#xff0c;而 pdf2image 是一个用于将 PDF 转换为图…

结构体基础全家桶(2)结构体指针

目录 指向结构体类型数据的指针&#xff1a; 指向结构体变量的指针&#xff1a; 创建&#xff1a; 应用&#xff1a; 注意事项&#xff1a; 指向结构体数组的指针 创建&#xff1a; 应用&#xff1a; 注意&#xff1a; 用结构体变量和指向结构体的指针做函数的参数 …

eNSP小实验---(简单混合)

实验目的&#xff1a;实现vlan10 vlan20 172网段用户互访 1.拓扑图 2.配置 PC1 其它同理 SW4 <Huawei> <Huawei>u t m Info: Current terminal monitor is off. <Huawei>sys <Huawei>sys Enter system view, return user view with CtrlZ. [Hua…

K8s(九)—volume.md

目录 volumeconfigMap介绍官网例子基于文件生成 ConfigMap使用 ConfigMap 数据定义容器环境变量使用单个 ConfigMap 中的数据定义容器环境变量 EmptyDirhostPathhostPath 配置示例 nfspersistentVolumeClaim volume https://kubernetes.io/zh-cn/docs/concepts/storage/volume…

深度学习小白学习路线规划

作为深度学习的初学者&#xff0c;以下是一个建议的学习路线&#xff0c;可以帮助你逐步掌握图像分类、目标检测与跟踪、实例分割和姿态估计&#xff1a; 掌握这些&#xff0c;计算机视觉算是入门了&#xff01; 1. 基础知识&#xff1a; 学习Python编程语言&#xff0c;它是…

当在VMware Workstation Pro 中查询不到ens33网卡的IP

在学习中我们经常要去查询ens33的IP&#xff0c;但是有时候会查询不到&#xff0c;今天就遇到了这样的问题并且找到了解决方法 记录一下 ip a 查询不到IP 显示代码为 ens33: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether …

day18 根据一棵树的中序遍历与后序遍历构造二叉树

第一步&#xff1a;如果数组大小为零的话&#xff0c;说明是空节点了 第二步&#xff1a;如果不为空&#xff0c;那么取后序数组最后一个元素作为节点元素&#xff0c;找到根节点 第三步&#xff1a;找到后序数组最后一个元素在中序数组的位置&#xff0c;作为切割点 第四步…

[论文笔记] GAMMA: A Graph Pattern Mining Framework for Large Graphs on GPU

GAMMA: A Graph Pattern Mining Framework for Large Graphs on GPU GAMMA: 基于 GPU 的针对大型图的图模式挖掘框架 [Paper] [Code] ICDE’23 摘要 提出了一个基于 GPU 的核外(out-of-core) 图模式挖掘框架(Graph Pattern Mining, GPM) GAMMA, 充分利用主机内存来处理大型图…

〖大前端 - 基础入门三大核心之JS篇(55)〗- 内置对象

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;哈哥撩编程&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xff0c;目前在公司…

如何禁止孩子在电脑中浏览某些网页?

在使用电脑的过程中&#xff0c;我们会使用浏览器来查看网页。而在孩子使用电脑的过程中&#xff0c;有些网页并不适合孩子查看。因此&#xff0c;我们需要禁止孩子浏览不健康的网页。那么&#xff0c;该如何禁止孩子在电脑中浏览某些网页呢&#xff1f; 定时关机3000简介 定时…

LeetCode231. Power of Two

文章目录 一、题目二、题解 一、题目 Given an integer n, return true if it is a power of two. Otherwise, return false. An integer n is a power of two, if there exists an integer x such that n 2x. Example 1: Input: n 1 Output: true Explanation: 20 1 Ex…

QML 自定义进度条组件开发

一、效果预览 二、介绍&#xff1a; 自定义的QML 屏幕亮度拖动进度条组件CusProgressBar 可跟鼠标移动 更改进度条样式 三、代码 import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Controls.Material 2.12/***author:Zwj*csdn:来份煎蛋吧*date:2023/12/16*…

c/c++中 qsort 与 bsearch 算法的使用

------------------------------------------------------------ author: hjjdebug date: 2023年 12月 13日 星期三 17:30:41 CST descriptor: qsort & bsearch 算法的使用 ------------------------------------------------------------ qsort 用来排序,bsearch用来搜索…

2k小权值和

package tgb.第二章;import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Scanner;public class okt2k小权值和 {static int N(int) (2e57); // static Map<Integer, Integer> S new HashMap<Integer, Integer>() ;stat…

复盘理解/实验报告梳理 数据结构PTA实验二

一、列车厢调度 感觉这道题的题干有点难以读懂&#xff0c;或是有些地方介绍的比较含蓄。 先设置两个字符串&#xff0c;来接收进道顺序与出道顺序&#xff0c;题目的内容和那个知道入栈顺序求出栈顺序比较像。 从头循环遍历&#xff0c;检查配对&#xff0c;不配对的就入栈&am…

如何禁止服务器自动休眠

如何禁止服务器自动休眠 有时候服务器自己休眠&#xff0c;导致系统web站点无法访问&#xff0c;下面是解决办法&#xff01; 禁止服务器自动进入休眠状态的具体方法可能会因使用的Linux发行版而有所不同。以下是一些通用的方法&#xff0c;你可以根据你的系统选择适用的&#…

python之画动态图 gif效果图

import pandas as pd import matplotlib import matplotlib.pyplot as plt import os# set up matplotlib is_ipython inline in matplotlib.get_backend() if is_ipython:from IPython import displayplt.ion()def find_csv_files(directory):csv_files [] # 用于存储找到的…