接上一回C++:补继承漏洞+多态原理(带图详解)

引子:接上一回我们讲了继承的分类与六大默认函数,其实继承中的菱形继承是有一个大坑的,我们也要进入多态的学习了。

注意:我学会了,但是讲述上可能有一些不足,希望大家多多包涵

继承复习:

1,继承中的友元函数不能继承!(就比如说,你爸爸的朋友不是你朋友,你朋友不时你爸爸的朋友)

2,继承中的static:基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子 类,都只有一个static成员实例(可以通过地址来看是否一样)

继承补漏洞(数据冗余与二义性):

1. 什么是菱形继承?菱形继承的问题是什么?

菱形继承:菱形继承是多继承的一种特殊情况。

菱形继承有数据冗余和二义性的问题

如下图:西红柿,里面就有二个植物的属性,这与我们常识不符

2. 什么是菱形虚拟继承?如何解决数据冗余和二义性的

关键字:virtual ,虚拟继承可以解决菱形继承的二义性和数据冗余的问题

3. 继承和组合的区别?什么时候用继承?什么时候用组合?

继承其实是is a的关系,组合其实是has a 的关系

组合耦合度更低,关联性较低,比较适用与接口,继承耦合度更高,关联性比较强,比较收到父类的较大影响,往往一发而牵全身,故在现实生活,公司里能用组合就用组合,在继承的情况下就使用继承,(其实也是一种"黑箱白盒"的思想),白盒要求更高,黑盒则只要功能实现,故黑盒难度更低,而我们组合本质上就是一种黑盒,实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有 些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用 继承,可以用组合,就用组合。

多态基础知识:

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

多态的构成条件

1. 必须通过基类的指针或者引用调用虚函数

2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

虚函数:

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

抽象类:

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口 类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生 类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承

虚函数重写的两个例外:

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

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

试例代码:

class person
{
public:
    //virtual void ticket() = 0
    //在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口
    //类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生
        //类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承
    virtual void ticket()
    {
        cout << "买全票" << endl;
    }
    virtual ~person()
    {
        cout << "~person" << endl;
    }
};
class children :public person
{
public:
    virtual void ticket()
    {
        cout << "买半票" << endl;
    }
    ~children()
    {
        cout << "~children" << endl;
    }
};
class soldier :public person
{
public:
    virtual void ticket()
    {
        cout << "优先买票" << endl;
    }
    ~soldier()
    {
        cout << "~soldier" << endl;
    }
};
//产生多态的条件(语法规定)
//1,虚函数重写
//2,必须是父类引用调用虚函数或者父类指针

void func1(person &p)
{
    p.ticket();
}
void func2(person*p)
{
    p->ticket();
}


//协变
//析构函数的重写,编译器在编译的时候,统一变为destructor;
int main()
{
    person s1;
    children s2;
    soldier s3;
    func1(s1);
    func1(s2);
    func2(&s1);
    func2(&s2);
    func1(s3);
    func2(&s3);
    //隐藏关系大于重写
    s2.ticket();
    person* s4 = new soldier;
    person* s5 = new person;
    person* s6 = new children;
    delete s5;
    delete s4;
    delete s6;

    return 0;

}

多态的原理:

我们先看一下以下代码的结果:

//查看虚拟函数的地址-->虚表
//虚函数开辟有一定的空间消耗
    //参看各个虚函数的地址,与普通函数的区别
class Base
{
public:
    virtual void Func1()
    {
        cout << "Base::Func1()" << endl;
    }
    virtual void Func2()
    {
        cout << "Base::Func2()" << endl;
    }
    void Func3()
    {
        cout << "Base::Func3()" << endl;
    }
private:
    int _b = 1;
};
class Derive : public Base
{
public:
    virtual void Func1()
    {
        cout << "Derive::Func1()" << endl;
    }
private:
    int _d = 2;
};
void func(Base& p)
{
    //这是动态的一个(直接在虚表中找到的func)
    p.Func1();
    //静态编译的func(是在链接产生的符号表!)
    p.Func3();
}
//切割父类的那一部分!
int main()
{
    Base b;
    Base b2;
    Base b3;
    Derive d;
    func(b);
    func(d);
    int h1=2;
    static int h2=3;
    int* h3 = new int;
    const int h4=1;
    printf("栈区%p\n", &h1);
    printf("静态区:%p\n", &h2);
    printf("堆区:%p\n", &h3);
    printf("常量区:%p\n", &h4);
    //相关关系关联的成度
    printf("%p\n", *((int*)&b));
    printf("%p\n", *((int*)&d));
    /*printf("%p   ", &Base::Func1);
    printf("%p   ", &Base::Func2);
    printf("%p   ", &Base::Func3);
    printf("%p   ", &Derive::Func1);*/
    return 0;
}


结果运行如下:

一:虚函数指针存在对象中,有一个void**的指针

二:虚函数的地址相对其他非常相近,都是在代码区,

三,(1),多个虚函数地址如果类型一样,他们的地址都是一样的,就是共享虚表(2),注意取出前四位地址是*((int*)&b);(3),虚函数表,存在常量区

四,继承的虚函数地址没有改变,重写的虚函数地址改变,

多态原理文字解释(虚表本质是函数指针数组):

void->虚函数,存在代码区

void*->虚函数表,存在常量区

void**->虚函数表的指针,存在对象中

看出满足多态以后的函数调用,不是在编译时确定的,是运行 起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的。

其实多态本质上是一种动态绑定又称后期绑定。普通函数是静态绑定又称为前期绑定(早绑定),

什么是动态绑定与静态绑定?如下

1. 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态, 比如:函数重载 2. 动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体 行为,调用具体的函数,也称为动态多态。 3. 本小节之前(5.2小节)买票的汇编代码很好的解释了什么是静态(编译器)绑定和动态(运行时)绑定。

二道面试题:

多继承中指针偏移问题?下面说法正确的是(C )

class Base1 {  public:  int _b1; };

class Base2 {  public:  int _b2; };

class Derive : public Base1, public Base2 { public: int _d; };

int main(){ Derive d; Base1* p1 = &d; Base2* p2 = &d; Derive* p3 = &d; return 0; }

A:p1 == p2 == p3 B:p1 < p2 < p3 C:p1 == p3 != p2 D:p1 != p2 != p3

下面哪种面向对象的方法可以让你变得富有( ) '

A: 继承 B: 封装 C: 多态 D: 抽象

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

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

相关文章

windows环境下基于3DSlicer 源代码编译搭建工程开发环境详细操作过程和中间关键错误解决方法说明

说明: 该文档适用于  首次/重新 搭建3D-Slicer工程环境  Clean up(非增量) 编译生成 1. 3D-slicer 软件介绍 (1)3D Slicer为处理MRI\CT等图像数据软件,可以实行基于MRI图像数据的目标分割、标记测量、坐标变换及三维重建等功能,其源于3D slicer 4.13.0-2022-01-19开…

OS Copilot测评

1.按照第一步管理重置密码时报错了,搞不懂为啥?本来应该跳转到给的那个实例的,我的没跳过去 2.下一步重置密码的很丝滑没问题 3安全组新增入库22没问题 很方便清晰 4.AccessKey 还能进行预警提示 5.远程连接,网速还是很快,一点没卡,下载很棒 6.替换的时候我没有替换<>括…

【JavaEE】网络编程——UDP

&#x1f921;&#x1f921;&#x1f921;个人主页&#x1f921;&#x1f921;&#x1f921; &#x1f921;&#x1f921;&#x1f921;JavaEE专栏&#x1f921;&#x1f921;&#x1f921; 文章目录 1.数据报套接字(UDP)1.1特点1.2编码1.2.1DatagramSocket1.2.2DatagramPacket…

Spring Cloud Alibaba AI 介绍及使用

一、Spring Cloud Alibaba AI 介绍 Spring AI 是 Spring 官方社区项目&#xff0c;旨在简化 Java AI 应用程序开发&#xff0c;让 Java 开发者像使用 Spring 开发普通应用一样开发 AI 应用。而 Spring Cloud Alibaba AI 是阿里以 Spring AI 为基础&#xff0c;并在此基础上提供…

dive deeper into tensor:从底层开始学习tensor

inspired by karpathy/micrograd: A tiny scalar-valued autograd engine and a neural net library on top of it with PyTorch-like API (github.com)and Taking PyTorch for Granted | wh (nrehiew.github.io). 这属于karpathy的karpathy/nn-zero-to-hero: Neural Networks…

阐述 C 语言中的参数传递机制

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; &#x1f4d9;C 语言百万年薪修炼课程 通俗易懂&#xff0c;深入浅出&#xff0c;匠心打磨&#xff0c;死磕细节&#xff0c;6年迭代&#xff0c;看过的人都说好。 文章目…

多表查询sql

概述&#xff1a;项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系&#xff0c;分为三种&#xff1a; 一对多多对多一对一 一、多表关系 一对多 案例&#xff1a;部门与…

【PowerShell】-1-快速熟悉并使用PowerShell

目录 PowerShell是什么&#xff1f;和CMD的区别&#xff1f; PowerShell的演变 自动化IT管理任务 一些名词 详尽的PowerShell开始之路 1.打开PowerShell&#xff1a; 2.基本命令&#xff1a; &#xff08;1&#xff09;Get-Process &#xff08;2&#xff09;变量赋值…

【核心笔记】Java入门到起飞,小白都能看懂的Java教程 (五)——数组

一 数组的定义和初始化 定义数组 数据类型[] 数组名&#xff1b;例 int[] arr; 数据类型 数组名[]&#xff1b;例 int arr[]; 数组初始化 数据类型[] 数组名 new 数据类型[] {值}&#xff1b;例 int[] arr new int[] {1,2,3}; &#xff08;简化形式&#xff09;数据类型[] 数…

超赞!只需粘贴复制超赞,视频快速转换成文章

大家好&#xff01;我是闷声轻创&#xff01;是否还在为撰写高质量的文章而熬夜奋战&#xff1f;今天&#xff0c;我要给你们带来一个超级棒的消息——视频变文章的神奇工具&#xff0c;让你的创作之路从此不再艰辛&#xff01; 视频素材的宝藏——油管&#xff08;YTB&#xf…

2024年了还在学pytestday1

1、按照博主的说法&#xff0c;提出疑问&#xff1a;应该在电脑本地终端安装还是在pythoncharm终端安装&#xff1f; ------在pythoncharm终端安装就行 避免老是忘记&#xff0c;还是记下来比较好。 2、在公司安装不成功&#xff0c;换豆瓣源也不行&#xff0c;连接手机热点尝…

Linux--安装VMware步骤

安装VMware VMware Desktop Hypervisors for Windows, Linux, and Mac 复制链接打开浏览器下载即可 从官网下载软件&#xff0c;完成后为确保后续正常使用&#xff0c;需要检查虚拟网卡是否安装完成 检查虚拟网卡的安装步骤 Windows--设置--高级设置--网络适配器--看是否有显…

STM32杂交版(HAL库、音乐盒、闹钟、点阵屏、温湿度)

一、设计描述 本设计精心构建了一个以STM32MP157A高性能单片机为核心控制单元的综合性嵌入式系统。该系统巧妙融合了蜂鸣器、数码管显示器、点阵屏、温湿度传感器、LED指示灯以及按键等多种外设模块&#xff0c;形成了一个功能丰富、操作便捷的杂交版智能设备。通过串口…

vue2学习笔记-官网使用指南和搭建开发环境

官网使用指南 官网地址&#xff1a;介绍 — Vue.js 1、学习 1.1 教程和API 最重要的两个板块。API是VUE的字典&#xff0c;需要时来查阅。 1.2、风格指南 如何写出风格优雅的VUE代码。规则分为四类&#xff1a;必要的&#xff0c;强烈推荐、推荐、谨慎使用。 1.3、示例 …

初始网络知识

前言&#x1f440;~ 上一章我们介绍了使用java代码操作文件&#xff0c;今天我们来聊聊网络的一些基础知识点&#xff0c;以便后续更深入的了解网络 网络 局域网&#xff08;LAN&#xff09; 广域网&#xff08;WAN&#xff09; 路由器 交换机 网络通信基础 IP地址 端…

PCI PTS 硬件安全模块(HSM)模块化安全要求 v5.0

符合条件的 PCI SSC 利益相关者在 30 天的意见征询 (RFC) 期间审查 PCI PTS 硬件安全模块 (HSM) 模块化安全要求 v5.0 草案并提供反馈。 PCI PTS 硬件安全模块(HSM)模块化安全要求 v5.0图 从 7 月 8 日到 8 月 8 日&#xff0c;邀请符合条件的 PCI SSC 利益相关者在 30 天的意见…

C语言 结构体和共用体——结构体所占内存的字节数

目录 结构体所占内存的字节数 结构体所占内存的字节数

Unity之OpenXR+XR Interaction Toolkit实现 Gaze眼部追踪

使用 Unity OpenXR 实现Gaze眼部追踪 在虚拟现实(VR)和增强现实(AR)应用中,眼动追踪是一项强大而受欢迎的技术。它可以让开发者更好地理解用户的注意力和行为,并创造出更加沉浸和智能的体验。在本文中,我们将探讨如何使用 Unity OpenXR 实现Gaze眼部追踪功能。 Unity …

Linux文件:EXT2文件系统工作原理 软硬链接

Linux文件&#xff1a;文件系统究竟是什么&#xff1f;如何管理文件&#xff1f; 前言一、磁盘结构、存储策略1.1 磁盘存储结构1.2 磁盘存储策略1.3 磁盘的逻辑存储结构 二、如何管理磁盘文件三、如何管理组3.1 每个组保存的数据种类3.2 如何管理数据1、节点表&#xff08;inod…

智慧城市可视化页面怎么做?免费可视化工具可以帮你

智慧城市是一个综合性的概念&#xff0c;广泛应用于各个领域&#xff0c;如基础设施建设、信息化应用、产业经济发展、市民生活品质等。 可视化页面的制作也是一个综合性的过程&#xff0c;需要确定展示内容、数据收集与处理、设计可视化元素等多个环节紧密配合。 1. 明确展示…