多态——C++

这里写目录标题

  • 衔接继承总结
  • 继承和组合
    • 白箱复用
    • 黑箱复用
  • 多态的概念
  • 多态的定义以及实现
  • 虚函数重写的两个例外
    • 协变
    • 面试题
    • 析构函数的重写
  • final
  • voerride
  • 重载
  • 隐藏(重定义)
  • 重写(覆盖)
  • 抽象类
    • 什么是抽象类?
  • 实现继承和接口继承
  • 多态的原理
    • 虚函数表
  • 那多态的调用是怎么实现的呢?
  • 动态绑定和静态绑定
    • 切片的区别。
    • 多态的两种形态?
  • 单继承中的虚函数表
    • 虚表存在哪个区域?
  • 多继承中的虚函数表

衔接继承总结

继承的概念和定义,基类和派生类对象赋值转换,这点可以去学学。

一般子类继承级就用公有继承。

继承中的作用域就了解一下就OK。

虚拟继承半了解就行。
我们自己设计尽量不要用菱形继承。但是可以用多继承。

继承和组合

继承是有复用组合是相互独立

优先使用对象组合

白箱复用

在这里插入图片描述
继承这种通过生成派生类的复用称为白箱复用。因为基类的内部细节对子类可见,这样这一定程度破坏了封装。基类的改变,对派生类影响很大。派生类和基类的依赖关系很强,耦合度高。

黑箱复用

黑箱复用对象的内部细节不可见。没有很强的依赖关系,耦合度低
实际中多去使用组合,耦合度低,代码维护性好。

学软件工程一定要画UML图
要学会画类图

C只要不修改公有.就不会影响D。在这里插入图片描述
对象组合是类继承之外的另一种复用的选择。
C对象公有成员D不能直接用。
C对象保护成员D不能直接用。

多态的概念

多态就是:同一个对象去调用同一个函数时会产生不同的效果

多态的关键字是:virtual
在函数面前加上virtual就实现了多态。

构成条件
1.是虚函数+virtual
2.函数名/参数/返回值相同,构成重写,重写也叫作覆盖

注意:要和继承隐藏区分开,隐藏是没有+virtual。

多态有两个要求;
1.子类虚函数重写父类的虚函数。(重写就是三同+virtual)
(三同就是参数,返回值,函数名相同)
2.必须用父类指针或者引用去调用虚函数

为什么要用父类的?不能用子类的?因为只有父类的话,传参的话,符合对象赋值兼容的规则

不能用普通对象调用。

假如用普通对象调用,调用的都是普通对象的,也就是普通人的票
这点为什么不同呢?可以看下面的多态的实现原理。

多态的定义以及实现

怎么让不同的对象调用不同的函数,这里涉及到对象赋值转换,切割

#include <iostream>
using namespace std;
//普通票
class Person
{
public:virtual void BuyTicket(){cout << "买票——全价" << endl;}
};
//学生票 继承普通人
class Student :public Person
{
public:virtual void BuyTicket(){cout << "买票——半价" << endl;}
};
//教师票 继承普通人
class Teacher : public Person
{
public:virtual void BuyTicket(){cout << "买票——免费" << endl;}
};void Pay(Person* ptr)
{ptr->BuyTicket();
}
int main()
{Person p;Student s;Teacher t;Pay(&t);return 0; 
}

虚函数重写的两个例外

协变

这个是C++的缺陷。

首先满足协变,需要是对象

Student继承了Person,假如返回值不同,三同中的返回值不同。
子函数需要加virtual,这是好习惯。

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

面试题

接口继承。
子类 继承 重写父类虚函数
把virtual继承了下来,缺省参数也继承了下来。

1.接口继承(所以B中func不写virtual也是虚函数,复合多态条件,缺省参数也是用的A::func的1)

2.重写的函数实现。

析构函数的重写

析构函数+virtual构成重写,析构函数的名字统一会被改成destructer

基类的析构函数一般要定义为虚函数,定义为虚函数可以完成析构函数的重写。这样可以不容易导致析构的时候发生错误。

final

final中文叫做最后,可以理解为:最后的类。
1.在函数后面添加final关键字,修饰虚函数,表示该函数不能被重写
2.在基类的后面加final,表示该类不能被继承

voerride

override是写在子类中的,用于检查子类是否完成了重写,如果没有完成重写,就会报错
比如:
1.忘记加了virtual
2.函数仓鼠不同。

重载

1.两个函数在同一作用域
2.函数名/参数不同

隐藏(重定义)

隐藏针对的是两个普通函数
1.两个函数分别在基类和派生类的作用域
2.函数名相同
3.两个基类和派生类的同名函数不构成重写就是重定义(隐藏)。

重写(覆盖)

1.两个函数分别在基类和派生类的作用域
2.函数名/参数/返回值必须相同(协变除外)
3.两个函数必须是虚函数。

抽象类

概念:C++中的包含有纯虚函数的类就叫做抽象类抽象类的不能实例化处对象

子类继承抽象类,必须重写虚函数,才能实例化对象。

什么是抽象类?

抽象的意思就是:在现实中一般没有对应的实体
举个例子:

不能实例化出来对象。比如在学校中,不是具体的实体,而老师学生是具体的实体。

所以就是抽象类

抽象类间接要求子类必须重写,才能实例化对象

实现继承和接口继承

实现继承:普通函数的继承是实现继承。继承的是函数的实现,也就是函数体。

接口继承:虚函数的继承是接口继承,继承的是虚函数的参数/函数名/返回值继承的是接口,目的是为了重写,达成多态

所以不重写不实现多态,就不要虚函数

多态的原理

多态就是实现指针指向哪儿,调用哪的。
怎么实现的呢?

虚函数表

虚函数表里面存放的是虚函数的指针

父类的对象模型是:
1.指向虚函数表的指针
2.成员变量

子类的对象模型:
1.从父类继承下来的指针和变量
2.自己的变量

不同的是子类的虚函数表,在子类的虚函数表中,继承下来的重写的函数不一样

子类中重写的函数覆盖了父类的函数。

这就说明重写:是语法层的概念,对函数实现进行了重写。
原理层的概念:就是子类的虚表,拷贝父类的虚表,然后覆盖重写的那个虚函数

那多态的调用是怎么实现的呢?

多态调用的实现,依靠运行时决议,去指向对象的虚表查看调用函数的地址

普通函数的调用:编译时决议,编译时确定调用函数的地址


指向谁我在谁的虚表里找到调用的。
父类赋值给子类对象,也可以切片,为什么实现不了多态?

为什么对象实现不了多态。只有指针和引用可以实现

原理:编译器很死板,在编译的时候就确定了,编译器在检查时发现不构成多态

怎么才能让对象可以支持多态?对象是不可以的。

动态绑定和静态绑定

1.在程序编译期间确定了程序的行为,
2.构成多态就叫做动态绑定,也叫晚绑定,是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体函数

切片的区别。

对象的切片是把子类中父类的值,拷贝过去,自定义类型是深拷贝。
但是不拷贝虚表指针,因为都指向了同一个虚函数表。导致混乱,不知道调用谁。

对象切片的时候,子类只会拷贝成员给父类对象,不会拷贝虚表指针,假如拷贝就混乱了,父类对象中到底是父类的虚表指针,还是子类的虚表指针?到底该调用谁就混乱了。

但是多态是指向谁调用谁,这不就混乱了,父类指向子类调用的还是子类。所以对象不可能实现多态。

在这里插入图片描述在这里插入图片描述

但是引用和指针切片的话就是直接指向父类或引用父类的那一部分,不存在拷贝的苦恼

多态的两种形态?

静态的多态:函数重载。
为什么有静态的多态,重载实际是在编译期间,根据函数名修饰规则找到不同的函数。

动态的多态:就是上面所讲的。是在运行时候去指向的虚函数表找,而实现的两种形态。

在这里插入图片描述

单继承中的虚函数表

虚函数理论而言要进虚表,但如果只有子类有的虚函数,监视窗口只有父类的虚表,难道子类只有的虚函数不进虚表吗?编译器规定,虚函数都要进虚表的,但是子类一般是拷贝父类的的虚表,然后重写需要重写的虚函数进行覆盖。因为监视窗口一般都是骗人的。但在内存中可以看到。

为了验证这个现象,我们可以写一段程序来打印虚表

虚函数表是一个数组,数组里的每一个元素是函数指针。

这里说明vs的监视窗口看到的虚函数表不一定是真实的,可能会被处理过。

虚表存在哪个区域?

同一个类型的对象,共用一个虚表。
在这里插入图片描述

所以虚表存在的区域只有静态区(数据段)或常量区(代码段)
那么到底在哪个区域呢。
常量区
常量区更加合理,因为静态区一般是全局变量.

我们也可以打印来验证,会发现虚标的地址和常量区的地址最为接近

多继承中的虚函数表

多继承中虚函数表中虚函数的位置

派生类的未重写的虚函数会放在继承的第一个基类部分的虚函数表。

在这里插入图片描述

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

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

相关文章

从零开始HashMap

目录 1.HashMap的数据结构 2.put&#xff08;&#xff09;流程 2.1了解扩容机制 2.2扩容三个地方 2.3存入数据步骤 3.HashMap和Hashtable的区别 4.HashMap线程安全的解决办法 4.1Hashtable 4.2Collections 4.3ConcurrentHashMap 线程安全实现机制 1.HashMap的数据结…

14届蓝桥杯 C/C++ B组 T6 岛屿个数 (BFS,FloodFill,填色)

首先拿到这道题不要想着去直接判断环里面的岛屿&#xff0c;这样太困难了&#xff0c;我们可以使用之前做过的题的经验&#xff0c;在输入加入一圈海水&#xff0c;然后从(0,0)点开始BFS&#xff0c;这里进行八向搜索&#xff0c;搜到的0全部都染色成2&#xff0c;假如2能够蔓延…

Vue项目打包配置生产环境去掉console.log语句的方法

一、Vue2项目 使用webpack内置的 terser 工具&#xff0c;在vue.config.js文件加上相应的配置即可。 二、Vue3项目 同样是使用 terser 工具&#xff0c;不过vite没有内置terser&#xff0c;需要手动安装依赖 安装完后在vite.config.js文件加上相应的配置即可。 2024-4-9

日本韩国海外网红达人合作:共创TikTok与YouTube双赢营销格局

【本篇由言同数字科技有限公司原创】日韩地区拥有庞大的互联网用户群体&#xff0c;其中TikTok和YouTube作为两大主流平台&#xff0c;吸引了大量的用户和网红。随着直播带货在全球范围内的兴起&#xff0c;日韩地区的网红们也开始积极参与直播带货&#xff0c;将其作为一种新的…

如何使用pandoc转word和正确的参考文献格式

如何使用pandoc转word和正确的参考文献格式 latex转word参考文献样式 .csl 文件获取方法&#xff1a; bib转ris 在线转换导入endnote文献管理工具 latex转word 在cmd中转到latex文件所在目录&#xff0c;运行&#xff1a; pandoc sn-article.tex -o output_1.docx -w docx --…

VRRP——虚拟路由冗余协议

什么是VRRP 虚拟路由冗余协议VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;是一种用于提高网络可靠性的容错协议。 通过VRRP&#xff0c;可以在主机的下一跳设备出现故障时&#xff0c;及时将业务切换到备份设备&#xff0c;从而保障网络通信的连续性和可…

研华UNO-3082-BTO工控机维修Advantech工业计算机主机深圳捷达工控维修

Intel Core™ 2 双核自动化计算机 带双 DVI、2 x PCI 和 FireWire Intel Core™ 2 双核自动化计算机 带双 DVI、1 x PCIe、3 x PCI 和 FireWire 板载 Intel Core 2 Duo L7500 1.6 GHz 处理器 双 DVI-I 支持最多 3 个显示器 用于视觉检测设备的双 IEEE-1394 通过跳线选择 AT/AT…

php其他反序列化知识学习

简单总结一下最近学习的&#xff0c;php其他的一些反序列化知识 phar soap session 其他 __wakeup绕过gc绕过异常非公有属性&#xff0c;类名大小写不敏感正则匹配&#xff0c;十六进制绕过关键字检测原生类的利用 phar 基础知识 在 之前学习的反序列化利用中&#xff0…

kvm虚拟机磁盘镜像加密

一、qcow2的aes加密 低版本的qemu能够支持对qcow2文件进行aes加密的方式&#xff0c;例如对一个已经存在的磁盘文件test.qcow2&#xff0c;可以将其转换为经过加密的qcow2文件。 qemu-img convert -O qcow2 --object secret,idsec0,data123456 -o encryptionon,encrypt.key-s…

(学习日记)2024.04.18:UCOSIII第四十六节:CPU利用率及栈检测统计

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

SQL explain 显示子查询A类型为ALL怎么优化

当 SQL EXPLAIN 显示子查询 A 的类型为 ALL 时&#xff0c;这意味着数据库系统正在执行全表扫描&#xff0c;而不是使用索引来执行子查询。全表扫描可能会导致性能下降&#xff0c;特别是在大型表上。 为了优化这种情况&#xff0c;您可以考虑以下几点&#xff1a; 1. **索引…

【Linux学习笔记】安卓运行C可执行文件No such file or directory

文章目录 开发环境运行失败现象解决办法方法一&#xff1a;使用静态库方法二&#xff1a;使用动态库创建lib查找依赖库复制需要注意的事情 开发环境 开发板&#xff1a;正点原子RK3568开发板安卓版本&#xff1a;11可执行程序命名&#xff1a;ledApp需加载模块&#xff1a;dts…

Redis的过期策略与内存淘汰机制原理及实践

Redis作为高性能的键值存储系统&#xff0c;其对数据过期与内存管理的设计直接影响到系统的性能与资源利用率。本文将以生动的比喻、通俗的语言&#xff0c;深入剖析Redis的过期策略与内存淘汰原理&#xff0c;助您全面理解数据在Redis中的生命周期管理艺术。 一、Redis过期策…

在线程间共享数据---互斥量

在线程间共享数据—互斥量 std::mutex std::mutex 是C标准库中 <mutex> 头文件中定义的一个类&#xff0c;它是实现多线程同步的基础工具&#xff0c;主要用于保护共享资源&#xff0c;防止多个线程同时访问同一资源造成的数据竞争&#xff08;race condition&#xff0…

Ubuntu安装配置FTP

1、安装服务端 sudo apt-get install vsftpd service vsftpd start service vsftpd stop service vsftpd restart 2、创建目录、用户 mkdir -p /home/xxxx sudo useradd -g ftp -d /home/vsftp -m angler 命令一&#xff1a;这种命令会在登录界面显示用户名 sudo …

vue3大事件项目3

弹框验证 先准备变量: const formModel ref({ cate_name: , cate_alias: }) 还有规则&#xff1a; const rules { cate_name: [ { required: true, message: please input name, trigger: blur }, { pattern: /^\S{1,10}$/, message: must be 1-10, trigger: blur } ], …

Java 基于微信小程序的智能停车场管理小程序

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Rust腐蚀服务器常用参数设定详解

Rust腐蚀服务器常用参数设定详解 大家好我是艾西&#xff0c;一个做服务器租用的网络架构师上期我们分享了rust腐蚀服务器的windows系统搭建方式&#xff0c;其中启动服务器bat参数因为涉及的东西比较多所以想通过这篇文章给大家做一下详细的分享。 &#xff08;注本文中xxxx…

浅述.Net中的Hash算法(顺带对称、非对称算法)

【写在前面】 对称加密算法(只有一个私钥&#xff0c;比如DES【不推荐】、AES)&#xff1b; 非对称加密算法&#xff08;公钥与私钥&#xff0c;比如RSA&#xff09;&#xff1b; Hash算法也称为散列函数算法&#xff0c;任意长度的数据都转换为固定长度的字符串&#xff08…

【自然语言处理八-transformer实现翻译任务-一(输入)】

自然语言处理八-transformer实现翻译任务-一&#xff08;输入&#xff09; transformer架构数据处理部分模型的输入数据(图中inputs outputs outputs_probilities对应的label)以处理英中翻译数据集为例的代码 positional encoding 位置嵌入代码 鉴于transfomer的重要性&#xf…