当前位置: 首页 > news >正文

多态的使用和原理(c++详解)

一、多态的概念

        多态顾名思义就是多种形态,它分为编译时的多态(静态多态)运行时的多态(动态多态),编译时多态(静态多态)就是函数重载,模板等,通过不同的参数来完成对不同的函数的调用(即生成多种形态)并且这个过程在编译阶段就已经完成

        动态多态是在运行时根据对象的实际类型来确定调用函数的哪个版本,完成不同的⾏为。

二、多态构成条件

1.虚函数

        在类成员函数的返回类型前面添加virtual关键字即为虚函数,注意:虚函数只能定义于普通成员函数,构造函数以及类外函数不能定义虚函数。

2.虚函数的重写

        虚函数重写指的是子类(派生类)对父类(基类)的重写。重写的要求是子类虚函数的返回值,函数名,参数类型必须和父类一模一样。但函数的实现逻辑不用相同。

        这里如果虚函数的重写没有加virtual,但是父类加了virtual那么子类依旧保持virtual的性质,也可构成重写。

        注意:对虚函数重写并没有要求缺省参数要相同,但在这里强烈建议把缺省参数设为相同值,要不然会给你带来很大的弊端和误导性。接下来我会讲到。

3.调用方式

        要实现多态效果,第⼀必须是基类的指针或引⽤,因为只有基类的指针或引⽤才能既指向派⽣类对象又能指向基类;第⼆派⽣类必须对基类的虚函数重写/覆盖,重写或者覆盖了,派⽣类才能有不同的函数,多态的不同形态效果才能达到。

⽐如火车买票这个操作,当普通⼈买票时,是全价买票;学⽣买票时,是优惠买票;军⼈买票时是优先买票,我们就可以用多态来实现,如下:

#include<iostream>
using namespace std;
class ticket
{
public:virtual void func(){cout << "普通票" << endl;}
private:
};
class student:public ticket
{
public:virtual void func(){cout << "学生票" << endl;}
private:
};
void fm(ticket& pu)
{pu.func();
}
int main()
{ticket tk;student stu;fm(tk);fm(stu);return 0;
}

4.override和final的修饰

        override关键字:因为多态的实现细节要求太多了特别是对虚函数的重写,因此C++11提供了override,可以帮助⽤⼾来检查虚函数的重写是否正确,需要放在重写的函数参数列表后面。

        final关键字:如果不想子类对该虚函数进行重写的话就可以使用final关键字,放在函数名后面。

5.协变 

        刚才我们说了虚函数的重写一定要满足子类虚函数的返回值,函数名,参数类型必须和父类相同。协变是个例外情况。当子类重写父类虚函数时,若与父类虚函数返回值类型不同,即父类虚函数返回父类对象的指针或引用,子类虚函数返回子类对象的指针或引用,此时称为协变。协变的实际意义并不⼤,所以我们了解⼀下即可。

代码示例:

class A{};
class B :public A{};
class ticket
{
public:virtual ticket* func()//ticket也可以是A{cout << "普通票" << endl;return this;}
private:
};
class student:public ticket
{
public:virtual student* func() override//student也可以是B{cout << "学生票" << endl;return this;}
private:
};

析构函数的重写

        父类的析构函数为虚函数,此时派⽣类析构函数只要定义,⽆论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派⽣类析构函数名字不同看起来不符合重写的规则,实际上编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统⼀处理成destructor所以基类的析构函数加了vialtual修饰,派⽣类的析构函数就构成重写

A* p1 = new A;
A* p2 = new B;
delete p1;
delete p2;

        假设B是A的子类上⾯的代码如果~A(),不加virtual,那么delete p2时只调⽤A的析构函数,没有调⽤B的析构函数,就会导致内存泄漏问题。

三、纯虚函数和抽象类

        在虚函数的参数列表后⾯写上=0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被子类重写,但是语法上可以实现),只要声明即可。包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象如果子类继承后不重写纯虚函数,那么子类也是抽象类。纯虚函数某种程度上强制了子类重写虚函数,因为不重写实例化不出对象。

四、多态原理

        在分析对象的储存空间时,我们讲过对于同一个类实例化出的不同对象,这些对象使用的函数都是相同的,不同的是它们成员变量。所以每个对象只需要对成员变量进行储存,不用对成员函数进行储存,每一个对象使用的都是这个类的公共成员函数。

        c++为虚函数单独设立了一块区域来储存虚函数的地址,叫做虚表,而这块区域其实 就是一个函数指针数组。即用来储存函数指针的一个数组。那么父类和子类就各自有一个虚表,在对象实例化的时候就会隐含(隐含:类似于成员函数里面看不见的this指针一样)着一个指针——虚表指针,来指向虚表。

#include<iostream>
using namespace std;
class A
{
public:virtual void func(){}
};
class B
{
public:void func(){}
};
int main()
{A a;B b;cout << "a:" << sizeof(a) << endl;cout << "b:" << sizeof(b) << endl;return 0;
}

而虚表指针也是需要占用空间的大家可以自行地去运行一下以上代码,输出结果为:

a:4(或8,即32位与64位机器的区别)

b:1

        所以在调用对象的虚函数时就跟以什么类型的形式调用无关,而是跟这个对象实例化时具体类型有关。

#include<iostream>
using namespace std;
class ticket
{
public:virtual void func(){cout << "普通票" << endl;}
};
class student :public ticket
{
public:virtual void func() {cout << "学生票" << endl;}
};
int main()
{ticket* tk = new student;tk->func();return 0;
}

以上的输出结果是“学生票”。

注意:根据切片原理,子类可强制类型转化为父类,父类不能强制类型转化为子类。

五、练习

以下程序输出结果是什么()

  • A:A->0
  • B:B->1
  • C:A->1
  • D:B->0
  • E:编译出错
  • F:以上都不正确

        这里虽然B类的func成员没有写virtual关键字,但它是由A继承下来的依旧保留virtual的性质,然后因为重写并为要求参数的缺省值相同,所以这里构成函数的重写。再来看主函数main,p调用了test,而test是A的成员函数隐含了一个const   A* (this指针)的参数类型,p传到test函数满足多态,所以这里调用的是B的func。但是这里有个坑,该题的输出结果并不是“B->0”,而是“B->1”。

        要注意重写只是重写了函数的实现,也就是说实现多态的时候相当于调用的是父类的接口声明和子类的函数实现,而并不关心子类的函数接口声明。

        所以在我们自己写虚函数的时候,最好把缺省参数设为相同值,要不然会给你带来很大的误导性。

相关文章:

多态的使用和原理(c++详解)

一、多态的概念 多态顾名思义就是多种形态&#xff0c;它分为编译时的多态&#xff08;静态多态&#xff09;和运行时的多态&#xff08;动态多态&#xff09;&#xff0c;编译时多态&#xff08;静态多态&#xff09;就是函数重载&#xff0c;模板等&#xff0c;通过不同的参数…...

OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【Trace调测】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 基本概念 Trace调测旨在帮助开发者获取内核的运行流程&#xff0c…...

Lombok 在 IntelliJ IDEA 中的使用步骤

Lombok 是一个非常流行的 Java 库&#xff0c;它通过注解简化 Java 类的开发&#xff0c;特别是在处理 POJO&#xff08;Plain Old Java Objects&#xff09;类时&#xff0c;如生成 getter、setter、toString 等常用方法。Lombok 在减少样板代码&#xff08;boilerplate code&…...

计算机网络 --- Socket 编程

序言 在上一篇文章中&#xff0c;我们介绍了 协议&#xff0c;协议就是一种约定&#xff0c;规范了双方通信需要遵循的规则、格式和流程&#xff0c;以确保信息能够被准确地传递、接收和理解。  在这篇文章中我们将介绍怎么进行跨网络数据传输&#xff0c;在这一过程中相信大家…...

git笔记之在多个分支中复用某个分支提交的更改

git笔记之在多个分支中复用某个分支提交的更改 code review! 文章目录 git笔记之在多个分支中复用某个分支提交的更改1.实现该功能的 Bash 脚本示例2.这个脚本是否可以处理新添加的文件&#xff1f;3.该脚本使用前&#xff0c;应先使用下述脚本重置本地仓库所有分支与远程保持一…...

HTML、CSS

初识web前端 web标准 Web标准也称为网页标准&#xff0c;由一系列的标准组成&#xff0c;大部分由W3C (World Wide Web Consortium&#xff0c;万维网联盟) 负责制定。三个组成部分: HTML: 负责网页的结构(页面元素和内容)。CSS: 负责网页的表现(页面元素的外观、位置等页面样…...

数据文件(0)

一、使用场景 1、字典数据 对于一些数据量不大的配置类数据&#xff0c;放到数据库中占用数据库资源&#xff0c;可以放到代码中维护。比如 &#xff08;1&#xff09;字段少业务单一&#xff1a;做成枚举&#xff1b; &#xff08;2&#xff09;字段多业务复杂&#xff1a…...

Go语言并发模式详解:深入理解管道与上下文的高级用法

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在Go语言中,并发编程是其最强大的特性之一。合理地使用并发模式,可以让我们的程序高效而优雅地处理复杂的任务。在本文中,我们将深入探讨Go语言中的一些高级并发模式,包括管道的技巧和上下文包的应用。通过丰…...

标准文档流解析及 CSS 中的相关特性

目录 非 VIP 用户可前往公众号回复“css”进行免费阅读 标准文档流特点 空白折叠现象 高矮不齐、底边对齐 自动换行,一行写不满,换行写 标准文档流中的元素等级 HTML 与 CSS 中的标签分类总结 块级元素和行内元素的相互转换 块级转行内 行内转块级 display 非 VIP…...

水下攻防面试题

水下攻防面试题通常涉及对水下环境的理解、水下安全操作、水下技术应用以及攻防策略等多个方面。由于具体的面试题可能因组织、职位和目的的不同而有所差异,以下是一些可能出现在水下攻防面试中的典型问题及其参考答案框架: 一、基础概念与理解 什么是水下攻防? 水下攻防是…...

vmware 虚拟机多屏幕或添加屏幕

vmware 虚拟机多屏幕或添加屏幕 前置条件 vmware 安装 vmware tools 虚拟机系统支持多屏幕 物理上有至少两个屏幕&#xff0c;就是物理机上接至少一个屏幕 方法 虚拟机上点设置&#xff0c;需要在虚拟机关机时进行 ctrl alt enter 让当前虚拟机全屏 鼠标移动到屏幕虚拟机…...

鹏哥C语言49-51---第6次作业:循环语句 for 和 while

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> //-----------------------------------------------------------------------------------------------第六次作业&#xff1a;for循环等 //--------------------------------------------------------------------…...

springboot中药材进存销管理系统

基于springbootvue实现的中药材进存销管理系统 &#xff08;源码L文ppt&#xff09;4-079 4 系统总体设计 4.1系统功能结构设计图 根据需求说明设计系统各功能模块。采用模块化设计方法实现一个复杂结构进行简化&#xff0c;分成一个个小的容易解决的板块&#xff0c;然…...

GitHub上图像超分开源项目推荐【持续更新】

SRCNN 介绍&#xff1a;SRCNN&#xff08;Super-Resolution Convolutional Neural Network&#xff09;是一种用于图像超分辨率的卷积神经网络。它由Dong等人在2014年提出&#xff0c;是早期的深度学习方法之一&#xff0c;用于提高图像的分辨率。SRCNN通过学习低分辨率&#…...

浅谈软件测试的基础知识(1)

文章目录 一、什么是测试1.1、生活中的测试案例1.2、为什么需要进行软件测试 二、测试和开发的区别2.1、调试和测试的区别 四、测试人员需具备哪些素质五、软件的生命周期六、软件测试的生命周期七、设计测试用例的方法[!]7.1、什么是测试用例7.2、测试用例作用 八、走测试岗位…...

Mac 上哪个剪切板增强工具比较好用? 好用剪切板工具推荐

在日常文字编辑中&#xff0c;我们经常需要重复使用复制的内容。然而&#xff0c;新内容一旦复制&#xff0c;旧内容就会被覆盖。因此&#xff0c;选择一款易用高效的剪贴板工具成为了许多人的需求。本文整理了一些适用于 macOS 系统的优秀剪贴板增强工具&#xff0c;欢迎大家下…...

基于opencv的车牌检测和识别系统(代码+教程)

车牌检测与识别技术详解 车牌检测和识别&#xff08;License Plate Recognition, LPR&#xff09;是一项重要的计算机视觉任务&#xff0c;它在交通管理、安全监控以及智能门禁系统等多个领域都有着广泛的应用。随着深度学习技术的发展&#xff0c;LPR系统的准确性和鲁棒性得到…...

list(二) (list模拟实现)

首先进行大框架 先写基本的结点类 有data next prev template<class T>class ListNode//或者使用struct 就不用在写public声明公有{public://这里不仅仅是成员函数 成员变量也要公有化 ListNode<T>* _next;ListNode<T>* _prev;T _data;}之后是链表list类…...

[Linux]从零开始的泰山派系统安装与远程教程

一、前言 泰山派买回来也有一阵子了&#xff0c;最近慢慢开始研究。当然&#xff0c;学习这种Linux的开发板的第一步就是安装系统&#xff0c;对于RK系列的芯片系统安装有专门的软件&#xff0c;所有在系统安装方面比较简单。更多的还是我们应该怎么去编译系统&#xff0c;这一…...

Python国产新 ORM 框架 fastzdp_sqlmodel 快速入门教程

创建模型 from typing import Optional from sqlmodel import Field, SQLModel import fastzdp_sqlmodel as fasmclass Hero(SQLModel, tableTrue):id: Optional[int] Field(defaultNone, primary_keyTrue)name: strsecret_name: strage: Optional[int] None创建表 from ty…...

面试速通宝典——3

51. 野指针和内存泄漏是什么&#xff1f;如何避免&#xff1f; ‌‌‌‌  内存泄漏&#xff1a;是指程序中以动态分配的堆内存由于某种原因程序未释放或无法释放&#xff0c;造成系统内存的浪费&#xff0c;导致程序运行速度减慢甚至系统崩溃等严重后果。 ‌‌‌‌  避免&…...

每天一个数据分析题(四百七十三)- 元数据

下列哪些元素属于元数据内容&#xff1f; &#xff08;&#xff09; A. 名称 B. 长度 C. 类型 D. 取值范围 数据分析认证考试介绍&#xff1a;点击进入 题目来源于CDA模拟题库 点击此处获取答案 数据分析专项练习题库 内容涵盖Python&#xff0c;SQL&#xff0c;统计学…...

产品经理面试整理-练习常见面试问题

练习常见面试问题是准备产品经理面试的重要环节。掌握这些问题的回答思路,不仅能帮助你在面试中更加自信,还能展示你对产品管理的深入理解。以下是一些常见的产品经理面试问题,以及如何高效准备这些问题的指南。 1. 常见面试问题及回答思路 1.1 你如何定义产品成功? ●...

一步到位的智慧:BI可视化大屏在复杂环境中如何精准拾取目标

在可视化设计器中实现良好的组件拾取功能&#xff0c;是提升用户体验和设计效率的关键。它们不仅能够提升用户体验和操作效率&#xff0c;还能够增强设计的灵活性和精度&#xff0c;促进设计创新&#xff0c;并最终提升设计的质量和价值。因此&#xff0c;在可视化设计过程中&a…...

前端开发迎来新机会,全栈转型就靠这个!

在如今的开发世界&#xff0c;全栈开发者已成为许多前端开发者的新目标。随着技术的不断演进&#xff0c;前端不再局限于写页面和样式&#xff0c;而是逐渐向后端延伸&#xff0c;甚至触及数据库和云服务。如果你想在职业道路上更进一步&#xff0c;向全栈开发者靠拢&#xff0…...

关于less的基本使用

1、介绍及概述 1.1、解释 less 是方便开发人员书写CSS的一门预处理语言。浏览器只认识html /css /js格式的文件&#xff0c;所以直接引入.less文件&#xff0c;没有任何的效果&#xff0c;需要把less文件转换成css文件 1.2、概述 CSS弊端&#xff1a; 没有逻辑性、变量、函…...

python 将 aac 转为 mp3,保持原有目录结构

需要提前安装 FFmpeg import os import subprocess import time from concurrent.futures import ThreadPoolExecutor, as_completeddef convert_file(input_path, output_path):command [ffmpeg,-y, # 自动覆盖现有文件-i, input_path,-acodec, libmp3lame,-b:a, 192k,outpu…...

考研数据结构——C语言实现折半查找

首先定义了一个有序数组a&#xff0c;然后计算出数组的长度n。接着定义了一个要查找的元素x&#xff0c;值为79。binarySearch函数实现了二分查找算法&#xff0c;它接受数组、左右边界和目标值作为参数&#xff0c;通过不断缩小搜索范围来查找目标值。如果找到了目标值&#x…...

【游戏引擎】C++自制游戏引擎 Lunar Game Engine

Lunar-Game Engine 仓库位置 Lunar Game Engine Lunar GameEngie是几个渣渣业余写的基于C的游戏引擎。 相比于比较成熟的引擎&#xff0c;该引擎的特点如下 结构,标准混乱bug众多根本不能用&#xff01; 最后的最后 To The Moon and Beyond! 简介 Luna Engine基于 C 和…...

使用【Sa-Token】实现Http Basic 认证

使用Sa-Token开源架构快速实现Http Basic 认证&#xff0c;如上图 1、springboot环境下直接添加starter即可 <!-- Sa-Token 权限认证&#xff0c;在线文档&#xff1a;https://sa-token.cc --> <dependency><groupId>cn.dev33</groupId><artifactI…...