C++多态特性详解

目录

概念:

定义及实现:

虚函数重写的两个例外:

1.协变:

 2.析构函数的重写:

final关键字:

 override关键字:

多态是如何实现的(底层):

面试题:


概念:

        所谓多态就是,当去完成某个行为时,不同的对象会产生不同的状态,导致不同的结果。

举个简单的例子:当去一个景区旅游,成人买票是全价,儿童买票是半价,这就是一种典型的多态。还有个典型的例子:大家在使用某多多助力拿红包时,有的能拿到,有的却邀了几百个人还是拿不到,这可能就是一种多态,如果你是新用户,它就会让你拿到,如果你是老用户,它可能让你拿不到。(仅个人猜测)

定义及实现:

c++中构成多态需要满足2个条件:

1.父类的指针或者引用去调用虚函数。

2.完成虚函数的重写,满足三同(函数名,返回值,参数)。

上述的三同有特例,后面会讲,我们先来简单实现一下上面买票这个例子的多态:

 试试传子类的引用看看结果如何:

注意:虚函数不能写成全局的,只能写在类里面。虚函数和正常的成员函数一样都存在代码段。

虚函数重写的两个例外:

        上面讲到了虚函数重写需要满足三同,函数名,返回值,形参都要保证和父类里面的对应虚函数相同,但也有两个例外。

1.协变:


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

 

不一定返回自己的父类或者子类,别的父类或者子类也可以:

 2.析构函数的重写:

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

看下面这个场景:

因为有切片的概念,父类的指针可以指向子类,注意看这里调用了两次父类的析构,但我们new出来的时一个父类和一个子类,这里看似没什么影响,但我们稍微对子类修改一下 :

这时如果不调用子类的析构就会造成内存泄漏,解决办法:

 结论:建议将析构函数写成虚函数,防止内存泄漏。

final关键字:

        当final修饰虚函数时,则改虚函数不能被重写:

        当final修饰一个类时,这个类为最终类,无法被继承:

 override关键字:

        加到子类重写的虚函数检查是否完成重写:

多态是如何实现的(底层):

 看下面这个场景

A里面明明只有一个变量_a,虚函数func是存在代码段的,没在类里面,按理来说应该算出4字节为何这里是16字节?

答:一旦类里面有虚函数,类的头4个(32位机器)或者8个(64位机器)字节就会有一个虚表指针 ,我这里是64位机器,然后又要满足结构体对齐,所以是16,我们用监视窗口看一下:

确实有个虚表指针,它指向该类虚函数的地址:

 想必已经猜出来了,虚表指针,指向的就是该类中所有虚函数的起始地址。

相同类型的类共用一个虚表,也就是虚表指针是相同的。 

当我们在子类对虚函数进行重写后,子类的虚表就存的是重写后的虚函数,父类的虚表存的还是重写前的虚函数,当我们用父类或者子类的引用或者指针去访问虚表时,就会访问到不同的虚表,从而完成不同的行为,构成多态。

那要是多继承,虚表指针是怎么存的呢?

再复杂点,多继承中的菱形继承又是怎么存虚表指针的呢?

此时D中的结构就如下图:

 再再再复杂一点,多继承中的菱形虚拟继承又是怎么存虚表指针的?

 此时D中的结构就如下图:

虚基表指针的知识我以后会讲 。

注意:虚表是存在常量区的,不是存在类里面,只是虚表指针存在类的头4个或者8个字节。 

面试题:

该程序运行的结果是什么?

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

因为虚函数的重写,重写的只是定义,它的形参的缺省值用的还是父类里面的。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

图像识别及分类

⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计3077字,阅读大概需要3分钟 🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号&#xf…

【网络编程下】五种网络IO模型

目录 前言 一.I/O基本概念 1.同步和异步 2.阻塞和非阻塞 二.五种网络I/O模型 1.阻塞I/O模型 2.非阻塞式I/O模型 ​编辑 3.多路复用 4.信号驱动式I/O模型 5. 异步I/O模型 三.五种I/O模型比较​编辑 六.I/O代码示例 1. 阻塞IO 2.非阻塞I/O 3.多路复用 (1)select …

Rust web简单实战

一、使用async搭建简单的web服务 1、修改cargo.toml文件添加依赖 [dependencies] futures "0.3" tokio { version "1", features ["full"] } [dependencies.async-std] version "1.6" features ["attributes"]2、搭…

【Leetcode每日一题】 综合练习 - 全排列 II(难度⭐⭐)(71)

1. 题目解析 题目链接:47. 全排列 II 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 2.算法原理 算法思路梳理 为了生成给定数组nums的全排列,同时避免由于重复元素导致的重复排列,我们可以遵…

刷代码随想录有感(56):二叉搜索树的最小绝对差

题干&#xff1a; 代码:中序遍历成有序数组逐一比较相邻两个数之间的差值&#xff0c;注意这里是取最小值所以定义的初始值应该是非常大的INT_MAX&#xff01;&#xff01;&#xff01; class Solution { public:void traversal(TreeNode* root, vector<int>&a){if(…

OpenCV 为轮廓创建边界框和圆(62)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV检测凸包(61) 下一篇 :OpenCV如何为等值线创建边界旋转框和椭圆(62) ​ 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 cv::boundingRect使用 OpenCV 函数 cv::mi…

c++多线程2小时速成

简介 c多线程基础需要掌握这三个标准库的使用&#xff1a;std::thread,std::mutex, andstd::async。 1. Hello, world #include <iostream> #include <thread>void hello() { std::cout << "Hello Concurrent World!\n"; }int main() {std::th…

轻松应对数据恢复挑战:雷神笔记本,不同情况不同策略

在数字化时代&#xff0c;数据无疑是我们生活中不可或缺的一部分。无论是重要的工作文件、珍贵的家庭照片&#xff0c;还是回忆满满的视频&#xff0c;一旦丢失&#xff0c;都可能给我们的生活带来诸多不便。雷神笔记本作为市场上备受欢迎的电脑品牌&#xff0c;用户在使用过程…

ubuntu使用Remmina远程连接Windows桌面

概况 目的&#xff1a; 远程连接公司电脑写一点代码 之前的方案&#xff1a; 安装Win10虚拟机&#xff0c;虚拟机里连接 VPN&#xff0c; 然后用 mstsc 命令连接。 新的方案&#xff1a;连接VPN后&#xff0c; 开启Remmina直接连接远程 Windows 桌面 新方案优点&#xff1a…

分布式锁之-mysql

使用mysql实现分布式锁的方式这里演示两种&#xff1a; 1:基于 MySQL 实现的乐观锁 2:基于 MySQL 实现的悲观锁 数据库脚本 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for product_stock -- -----------------------…

【Python】机器学习之Sklearn基础教程大纲

机器学习之Sklearn基础教程大纲 1. 引言 机器学习简介Scikit-learn&#xff08;Sklearn&#xff09;库介绍安装和配置Sklearn 2. 数据预处理 2.1 数据加载与查看 - 加载CSV、Excel等格式的数据- 查看数据的基本信息&#xff08;如形状、数据类型等&#xff09;2.2 数据清洗…

Vue 组件间的数据绑定

在Vue组件中&#xff0c;v-model指令可以用来实现双向数据绑定。它用于将组件的属性和父组件中的数据进行双向绑定&#xff0c;使得当属性的值改变时&#xff0c;父组件中的数据也会相应地改变&#xff0c;并且当父组件中的数据改变时&#xff0c;属性的值也会相应地改变。 目…

【软考高项】三十一、成本管理4个过程

一、规划成本管理 1、定义、作用 定义&#xff1a;确定如何估算、预算、管理、监督和控制项目成本的过程作用&#xff1a;在整个项目期间为如何管理项目成本提供指南和方向 应该在项目规划阶段的早期就对成本管理工作进行规划&#xff0c;建立各成本管理过程的基本框架&…

使用docker-compose编排lnmp(dockerfile) 完成Wordpress

实验环境&#xff1a; 在已有docker环境和nginx镜像的基础上进行编排。 1、准备mysql容器目录及文件 2、dockerfile文件内容 3、my.cnf文件内容 4、准备php容器目录及文件 5、dockerfile文件内容 6、准备其他文件 7、编写docker-compose.yml文件 8、Docker Compose环境的实现…

Redisson 分布式锁和同步器

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 redisson 是基于redis的扩展库,使得redis除了应用于缓存以外,还能做队列…

AI学习指南-人工智能概述

欢迎来到人工智能的奇妙世界&#xff01;如果你是初学者&#xff0c;那么你来对地方了。今天&#xff0c;我们将一起探索人工智能&#xff08;AI&#xff09;的基本概念&#xff0c;看看它是如何分类的&#xff0c;它的应用有哪些&#xff0c;以及未来可能的发展方向。准备好了…

Django之单文件上传(以图片为例)

一&#xff0c;创建项目 初始化&#xff0c;数据迁移&#xff0c;创建superuser&#xff0c;创建app等 二&#xff0c;配置settings.py 1&#xff0c;配置数据库&#xff08;本作者使用的mysql&#xff09;&#xff0c;以前文章有提到 2&#xff0c;配置静态文件存放路径 STAT…

Spring Cloud:探索它的核心组件,揭秘微服务生态

Spring Cloud简介 在我们的编程旅程中&#xff0c;我们会遇到各种各样的工具和技术&#xff0c;它们如同繁星般点缀在编程的天空中&#xff0c;而Spring Cloud就是其中一颗明亮的星。那么&#xff0c;什么是Spring Cloud呢&#xff1f; Spring Cloud&#xff0c;是一个基于Spr…

《尿不湿级》STM32 F103C8T6最小系统板搭建(五)BOOT

一、BOOT是什么&#xff1f; 大多数初学者第一次接触BOOT总是对这个词感到不解&#xff0c;从哪冒出一个奇奇怪怪的东西还要接跳线帽&#xff0c;为什么要配置它才能进行串口程序的下载&#xff1f;为什么不正确配置会导致单片机无法正常启动…… boot&#xff0c;及物动词&…

IOS 开发 - block 使用详解

1.Blobk的定义 block的写法相对难记,不必司机应被,只需要在xcode里打出"inlineBlock"--回车, 系统会自动帮你把基础版写法给你匹配出来 //Block的基础声明//等号""之前是blobk的声明,等号“”后面是block的实现/*returnType:返回类型(void、int、String *…
最新文章