面试二十四、继承多态

一、继承的本质和原理

 

 

 

        组合(Composition): 组合是一种"有一个"的关系,表示一个类包含另一个类的对象作为其成员。这意味着一个类的对象包含另一个类的对象作为其一部分。组合关系通常表示强关联,被包含的对象的生命周期通常受到包含它的对象的生命周期的限制。

示例:

class Engine {// Engine class definition
};class Car {Engine engine; // Car "has a" Engine// Other members and methods
};

继承(Inheritance): 继承是一种"是一个"的关系,表示一个类可以继承另一个类的属性和行为。子类(派生类)可以继承父类(基类)的成员和方法,并且可以添加新的成员和方法。继承关系建立了一个类层次结构,允许代码重用和实现多态。

示例:

class Animal {// Animal class definition
};class Dog : public Animal { // Dog "is a" Animal// Dog-specific members and methods
};

在C++中,structclass都是用于定义自定义类型(类)的关键字,它们有一些相同点和区别。

相同点:

  1. 成员变量和成员函数structclass都可以包含成员变量和成员函数。

  2. 访问控制structclass都支持访问控制修饰符publicprotectedprivate,用于控制成员的访问权限。

  3. 封装性structclass都支持封装性,即将数据和操作封装在一个单元中,隐藏内部实现细节,对外提供接口。

  4. 继承structclass都支持继承,可以通过派生类继承基类的成员和方法。

区别:

  1. 默认访问控制:在struct中,默认的成员访问级别是public,而在class中,默认的成员访问级别是private。这意味着,struct中定义的成员默认是公共的,而class中定义的成员默认是私有的。

  2. 继承访问控制:当使用class来定义一个继承关系时,默认的继承访问级别是private,而使用struct时,默认的继承访问级别是public。这意味着,如果你从class继承,派生类的成员默认为private;如果你从struct继承,派生类的成员默认为public

  3. 用法习惯:一般来说,struct更适合用来表示简单的数据结构,成员默认是公共的,不涉及复杂的封装;而class更适合用来表示有复杂行为的对象,需要进行更严格的封装和访问控制。

继承的本质可以总结如下:

  1. 代码重用:子类可以继承父类的成员变量和成员函数,无需重新实现相同的功能,从而实现代码的重用。

  2. 扩展性:子类可以添加新的成员变量和成员函数,从而扩展父类的功能,使其具有更多的行为。

  3. 多态性:继承是实现多态的基础。通过基类的指针或引用指向子类的对象,可以实现运行时多态性,即在运行时根据对象的实际类型调用相应的方法。

  4. 继承链:继承关系可以形成继承链,允许多层次的继承,子类可以继承父类的属性和行为,而子类的子类又可以继承子类的属性和行为,以此类推。

二、 派生类的构造过程

 三、重载、隐藏、覆盖

1. 函数的重载:

        函数重载(Function Overloading)是指在同一个作用域内,可以定义多个函数,它们具有相同的名称但是参数列表不同(参数的类型、个数或顺序不同),编译器根据调用时提供的参数来确定具体调用哪个函数。

        函数重载的主要特点包括:

  1. 相同的函数名:重载的函数具有相同的函数名。
  2. 不同的参数列表:重载的函数具有不同的参数列表,可以是参数的类型、个数或顺序不同。
  3. 在同一个作用域内:重载的函数必须在同一个作用域内定义。

        函数重载使得函数命名更加灵活,可以根据函数的功能和参数的类型选择合适的函数来调用,从而提高了代码的可读性和灵活性。

#include <iostream>// 函数重载示例
int add(int x, int y) {return x + y;
}double add(double x, double y) {return x + y;
}int add(int x, int y, int z) {return x + y + z;
}int main() {std::cout << "Sum of 3 and 5 is: " << add(3, 5) << std::endl; // 调用第一个 add 函数std::cout << "Sum of 3.5 and 2.5 is: " << add(3.5, 2.5) << std::endl; // 调用第二个 add 函数std::cout << "Sum of 2, 4, and 6 is: " << add(2, 4, 6) << std::endl; // 调用第三个 add 函数return 0;
}
2 基类和派生类 

        基类和派生类的show()不能说是重载,因为作用域不同。其是隐藏关系(隐藏的是作用域)。   如果派生类中没有show()函数,则可以调用基类的show()方法,但是如果派生类中存在show()同名的,不管参数列表,会将基类的show隐藏,包括基类中show函数的全部重载。

 3.继承的相互转换

指针的类型限制了指针的解引用能力 

 四、虚函数、静态绑定和动态绑定

1.typeid

        在C++中,typeid 是一个操作符,用于获取一个表达式的类型信息。它返回一个std::type_info 对象,该对象包含有关表达式类型的信息,如类名、基类等。std::type_info 是一个标准库类型,定义在 <typeinfo> 头文件中。通常,typeid 主要用于运行时类型识别(RTTI)和多态代码中。

        例如,你可以使用 typeid 来比较两个对象的类型是否相同,或者在运行时查找对象的实际类型以执行相应的操作。以下是一个示例:

#include <iostream>
#include <typeinfo>class Base {virtual void foo() {}
};class Derived : public Base {};int main() {Base* basePtr = new Derived();if (typeid(*basePtr) == typeid(Derived)) {std::cout << "basePtr 指向的对象是 Derived 类型" << std::endl;} else {std::cout << "basePtr 指向的对象不是 Derived 类型" << std::endl;}delete basePtr;return 0;
}
2. 静态绑定,没有虚函数,编译阶段就确定调用

 3.虚函数和虚函数表

  这里的show()加不加virtual,都是虚函数

        虚函数表(vtable)和虚函数表指针(vptr)是用于实现C++中虚函数机制的重要组成部分。它们的创建时机如下:

  1. 虚函数表(vtable)的创建时机:

    • 虚函数表是在编译阶段由编译器生成的。当一个类中包含至少一个虚函数时,编译器会在编译时生成该类的虚函数表。虚函数表是一个存储了该类中所有虚函数地址的数组,每个虚函数在表中占据一个位置,编译器会根据虚函数声明的顺序依次将其地址存入虚函数表中。
  2. 虚函数表指针(vptr)的创建时机:

    • 虚函数表指针是在运行时由编译器插入到对象的内存布局中的。当一个类包含虚函数时,每个对象都会包含一个虚函数表指针,用来指向该类的虚函数表。这个虚函数表指针(vptr)是在对象创建时初始化的,通常是在构造函数中完成初始化。当对象被销毁时,虚函数表指针也会被销毁。

 

4. 动态绑定

首先看指针的类型,然后看调用函数在父类中是正常的函数还是虚函数,如果是正常函数在编译的时候就知道了,如果是虚函数,先要查找子类的虚函数表(因为虚函数会被重写或者覆盖),然后调用函数,

 

【C++】RTTI有什么用?怎么用? - 知乎 (zhihu.com)

五、虚析构函数(new出来的派生类对象)

        在C++中,构造函数不能声明为虚函数。这是因为在构造对象时,需要确定构造函数的调用路径。如果构造函数是虚的,那么在构造对象时,需要在虚函数表中查找适当的构造函数。但是,在对象构造过程中,虚函数表尚未被设置,因此无法进行动态绑定。

        先构造函数,才有对象。

        静态成员方法不依赖于对象,就不会去对象中查询虚函数指针,不会去查虚函数表

         基类的析构函数会在派生类的析构函数执行完毕后被隐式调用。这是因为在派生类的析构函数中,会自动调用其直接基类的析构函数,然后依次向上调用每个基类的析构函数,直到调用完毕为止。

 

六、多态 

 

七、抽象类 

 八、类型转换

 

 九、多继承

1 虚继承和虚继承

 

 

1  是因为基类没有虚函数,才建的自己的虚函数指针和虚函数表

2. 是继承A的虚函数表和虚函数指针

2. 菱形继承  

 虚基类的数据搬到派生类中最后面,在原来的地方补vbptr

 

 

 

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

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

相关文章

Terrain —— Nodes

目录 Convert HeightField —— 转化高度场 HeightField —— 为地形创建初始高度场或遮罩场 HeightField Blur —— 模糊高度场或遮罩场 HeightField Clip —— 限制高度场的值 HeightField Combine Layers —— 将多个volume或VDB合并为一个新的volume或VDB HeightFiel…

我独自升级崛起怎么玩 我独自升级崛起游玩教程分享

《我独自升级&#xff1a;ARISE》是一款预计在 Android、iOS 和 PC 平台推出的动作 RPG&#xff0c;故事内容基于网络漫画版本改编&#xff0c;讲述世界各地出现「次元传送门」&#xff0c;而少部分人类觉醒了可以对抗传送门中怪物的「猎人」能力&#xff0c;玩家可以在故事模式…

【进程等待】是什么 | 为什么 | 怎么办 | wait阻塞等待

目录 进程等待是什么&#xff1f; 为什么要进程等待&#xff1f; 如何进程等待&#xff1f; wait 阻塞等待 进程等待是什么&#xff1f; 进程终止会把进程退出的数据&#xff08;退出码和退出信号&#xff09;存放到进程的PCB中保存下来&#xff0c;让父进程进行等待。…

【投稿资讯】区块链会议CCF C -- CoopIS 2024 截止7.10 附录用率

会议名称&#xff1a;CoopIS CCF等级&#xff1a;CCF C类学术会议 类别&#xff1a;人机交互与普适计算 录用率&#xff1a;2023年接收率21% (21 regular 10 work-in-progress papers/100) AREA 5: HUMAN-CENTRIC SECURITY AND PRIVACY IN INFORMATION SYSTEMS Access Con…

Linux网站服务

1.概念:HTML:超级文本编辑语言 网页:使用HTML,PHP,JAVA语言格式书写的文件。 主页:网页中呈现用户的第一个界面。 网站:多个网页组合而成的一台网站服务器。 URL:统一资源定位符&#xff0c;访问网站的地址。 网站架构:LAMP: LinuxApacheMYSQLPHP(系统服务器程序数据管理…

OpenHarmony 实战开发 - 如何在源码中编译复杂应用(4.0-Release)

文档环境 开发环境&#xff1a;Windows 11 编译环境&#xff1a;Ubuntu 22.04 开发板型号&#xff1a;DAYU 200&#xff08;RK3568&#xff09; 系统版本&#xff1a;OpenHarmony-4.0-Release 功能简介 在 OpenHarmony 系统中预安装应用的 hap 包会随系统编译打包到镜像中&a…

使用电路仿真软件教学的优势分析

随着科技的飞速发展&#xff0c;电子工程领域对人才的需求与日俱增。为了满足这一需求&#xff0c;教育者们不断探索着更加高效、直观的教学方法。电路仿真软件的出现&#xff0c;为电子工程教学注入了新的活力&#xff0c;它以其独特的优势&#xff0c;成为现代电子工程教育中…

啸叫抑制器采用什么处理芯片?ES56031或PH56031

会议系统或卡拉OK最头疼的就是啸叫了吧&#xff0c;来看看啸叫抑制器采用什么芯片 四通道啸叫抑制器&#xff0c;采用了2个电路板&#xff0c;每个板子处理2路信号&#xff0c;每块电路板有2个卡侬输入插座&#xff0c;2个卡侬输出插座 ES56031S&#xff0c;该啸叫抑制器为4通道…

请大数据把我推荐给正在申请小程序地理位置接口的人

小程序地理位置接口有什么功能&#xff1f; 若提审后被驳回&#xff0c;理由是“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通&#xff0c;建议完成接口开通后或移除接口相关内容后再进行后续版本提审”&#xff0c;那么遇到这种情况&#x…

软件可靠度计算

软件的整体可靠度依据&#xff1a;若是单个就是当前部件的可靠度。若是多个部件&#xff0c;就需要多个部件的可靠度相乘。若是多个部件且有相同备份&#xff0c;那么计算公式更加不一样。 计算公式&#xff1a; 部件数&#xff1a;N 部件可靠度均为&#xff1a;R 单个部件的可…

树莓派4b测量光照强度

1.BH1750光照强度连接图 2. BH1750工作原理 BH1750的通讯过程 第1步:发送上电命令。 发送的过程和第2步基本一致,把测量命令(0x10)改成上电命令(0x01)。第2步:发送测量命令。 下面图片上的例子,ADDR引脚是接GND的,发送的测量命令是“连续高分辨率测量(0x10)”。 发送数据…

oc渲染器如何设置调渲染更快?oc云渲染加速助力

OC渲染器是Cinema 4D软件中广泛使用的渲染工具&#xff0c;它利用GPU进行硬件加速渲染&#xff0c;具备强大的计算性能。这使得它能够为产品和动画制作人员提供卓越的渲染质量。此外&#xff0c;OC渲染器还支持云渲染技术&#xff0c;这在需要进行大规模渲染任务时非常有用&…

【商业】SD NAND(贴片式TF卡)性能体验及应用

SD NAND【商业】   外观   NAND与TF卡的区别   雷龙CS SD NAND(贴片式TF卡)性能体验及应用   最后 SD NAND 外观正反示意图 NAND与TF卡的区别 什么是SD NAND&#xff1f;它俗称贴片式T卡&#xff0c;贴片式TF卡&#xff0c;贴片式SD卡&#xff0c;贴片式内存卡&am…

【贪心算法】哈夫曼编码Python实现

文章目录 [toc]哈夫曼编码不同编码方式对比前缀码构造哈夫曼编码哈夫曼算法的正确性贪心选择性质证明 最优子结构性质证明 总结 Python实现时间复杂性 哈夫曼编码 哈夫曼编码是广泛用于数据文件压缩的十分有效的编码方法&#xff0c;其压缩率通常为 20 % 20\% 20%到 90 % 90\%…

【C++】——内存管理

&#x1f600;&#x1f600;前言 好久没更新了&#xff0c;五一小长假&#xff0c;有点玩脱了&#xff0c;今天赶紧补一篇博客&#xff0c;回回状态 一 c/c内存分配 下面看下面一段代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; i…

数据可视化训练第一天(matplotlib直线;散点图,随机漫步)

前言 本人自己的练习记录&#xff1b;如有错误请指正&#xff1b; https://matplotlib.org/stable/gallery/lines_bars_and_markers/index.html 官方有许多例子&#xff0c;可以找到自己需要的图像模仿进行绘制 1.一个简单的直线例子 就如同我们学习C语言的第一个helloword时…

STM32 PM2.5(GP2Y1014AU0F)空气质量 传感器

此工程是基于江科大源码的基础上创作&#xff0c;因为pm2.5这个模块比较冷门&#xff0c;参考的代码比较少&#xff0c;所以开源给大家学习参考&#xff01; 功能介绍 GP2Y10传感器模块模块原理&#xff1a;GP2Y1014AU0F是利用光散射发来测量空气中PM2.5的传感器&#xff0c;在…

Java集合进阶——集合体系结构及各个集合的方法

Java种的集合分为单列集合和双列集合&#xff0c;单列集合的最高层接口是Collection&#xff0c;双列集合的最高层是Map&#xff0c;这里先介绍单列集合 单列集合 体系结构&#xff1a; 注&#xff1a;红色框都为接口&#xff0c;蓝色框都为实现类&#xff08;实现类Vector已…

地平线的花样年华

北京车展在这个喧闹的“五一”假期落幕了&#xff0c;它留给我们许多思考。 虽然社会面的传播焦点落在了“网红”两个字上&#xff0c;但技术的更新依然如暗流涌动&#xff0c;给这届北京车展写下注脚。整个过程前后&#xff0c;最重要和吸引了最多目光的&#xff0c;是智驾&a…

什么是驱动数字签名?如何获取驱动数字签名?

Windows 驱动程序承载着计算机实现的各种内核和用户模式功能。如果驱动程序被黑客攻击&#xff0c;可能会产生很多问题。Windows通过数字签名来验证驱动程序包的完整性及发布者的身份。2020年10月的安全更新中&#xff0c;微软加强了对驱动软件的验证&#xff0c;如果Windows无…