C++面经

 

学习视频参考


1 面向对象的三大特征

1.1 封装

1.1.1 目的

隐藏实现细节,实现模块化。

1.1.2 特性

访问权限:

  • public:可以给所有对象访问。
  • protected:仅对子类开放。
  • private:仅对自己开放,可以通过友元进行访问。

能够对属性和方法进行限定。

1.2 继承

1.2.1 目的

在不修改原有类的情况下,通过继承实现功能的扩展。

1.2.2 特性

解决基类成员在子类中的最高权限

  • public:基类中的属性和方法原来是什么权限,在子类就还是什么权限。
  • protected:基类中的public权限在子类中会变成protected权限。
  • private:基类中的public和protected权限会变成private权限。解决基类成员在子类中的最高权限

注意基类的private权限在子类中存在但不能访问。

子类可以通过using修改基类在子类中的权限,这样就可以访问基类中private权限下的属性和方法。

多继承,C++可以继承多个父类。

 接口继承,存虚函数。

1.3 多态

1.3.1 目的

一个接口多种形态,通过实现接口重用,增强可扩展性。

1.3.2 特性

静态多态

  • 指编译器的多态。
  • 函数重载:同样的函数名不同的参数。

动态多态

  • 指运行时的多态。
  • 通过虚函数重写的方式实现。
  • 基类中有虚函数,子类通过重写基类的虚函数来实现多态。
  • 基类* p = new 子类;通过这种方式实现多态。

2 多态的实现原理

2.1 静态多态

2.1.1 函数重载

  • 允许同一作用域中声明多个功能类似的同名函数。
  • 其参数列表,参数个数,参数类型,参数顺序有所不同。
  • 不能通过返回值类型来区别函数重载。

2.1.2 原理

编译过程中

  • 预编译:把头文件中的函数声明拷贝到源文件当中去。避免编译过程中的语法分析找不到函数定义
  • 编译:语法分析,同时进行符号汇总。
  • 汇编:生成函数名和函数地址之间的映射。方便之后通过函数名找到函数定义位置,从而执行函数。
  • 链接:将多个文件中的符号表汇总合并。

通过函数名修饰达成函数重载的目的。

函数名修饰:在符号汇总中,相同函数名在符号表中的符号是不同的一般是函数名+有规则的前后缀。所以是编译器的多态。

2.2 动态多态

2.2.1 虚函数重写

虚函数重写,运行时确定。

  • 在基类的函数前+virtual关键字,在基类中重写该函数。
  • 运行时会根据对象的类型来调用相应的函数。
  • 如果对象的类型是基类,就调用基类的函数。
  • 如果对象的类型是子类,就调用子类的函数。

2.2.2 原理

  • 早绑定:编译器编译时已经确定了调用对象的函数地址。
  • 晚绑定:使用virtual函数,为类生成虚函数表—一个一维数组,存放了虚函数地址。类对象构造时会初始化该虚函数表指针。其中,虚函数表指针放在类的最前面的8个字节,指向虚函数表,虚函数表中存放类的虚函数地址。

3 菱形继承

3.1 什么是菱形继承

  • 前提:C++具备其他语言所没有的多重继承特性。
  • 原因:一个子类可以继承多个父类,而这些父类可能继承至相同的父类,这样就会造成菱形继承。

3.2 菱形继承有什么样的问题

一个类C,继承B1,B2,而B1,B2又继承至同一个类A。

那么构造类C的时候,我们的B1,B2是分别构造了自己的类A还是构造了不同的类A。也就是C的背后是有一个A还是有两个A?

一般情况下是构造了两个类A 这样就出现了如下的问题:

  • 造成存储空间的浪费。
  • 二义性。

3.3 解决方案

虚继承:

  • 目的:使得子类C只继承一次A。
  • 方法:继承的时候带上virtual关键字。
  • 原理:通过虚表偏移来实现虚继承。父类的虚指针都有到共同基类的偏移量,从而让子类多继承时能指向同一个  父类的父类。

感觉这个菱形继承一般不会有什么人用吧,毕竟其他语言也没有多继承这种东西。


4 override和final

C++11中引入这两个关键字

4.1 引入原因

  • 虚函数复写:1、不能阻止某个虚函数的进一步复写。2、本意是写一个新函数,结果复写了基类的虚函数。3、本意是重写虚函数,但是由于签名不一样导致子类中重新构建了一个虚函数。
  • 类继承:不能阻止某个类的进一步派生。

4.2 override

  • 指定子类的一个虚函数复写基类的一个虚函数。
  • 保证该重写的虚函数与基类的虚函数具体相同的签名。

解决虚函数复写中的3号问题。

4.3 final

  • 指定某个类不能被派生。
  • 指定某个虚函数不能再派生类中被覆写。

解决其他问题。


5 类型推导用法

5.1 类型:

  • 模板参数类型的推导。
  • auto。
  • decltype。

5.2 为什么要引入类型推导

  • C++是强类型语言。
  • 编译器来处理类型推导。
  • 提升语言的编码效率。

5.3 auto

5.3.1 原理:

  • 用于推导变量的类型,通过强制声明一个变量的初始值,编译器会通过初始值进行推导类型。

5.3.2 规则:

  • auto变量必须在定义时进行初始化。

  • 如果用auto定义多个变量,那么这些变量必须是同一类型。
  • 类型推导时会丢失引用&或者丢失const和volitte语义。
  • 保留引用或者cv语义,用auto &。
  • 万能引用使用auto &&。根据初始值的属性来判断是左值引用还是右值引用。
  • auto不能推导数组类型,推导的是数组头部指针。
  • C++14中auto可以推导函数的返回类型。

5.3.3 应用:

  • 尽量使用auto声明变量,除非影响可读性。
  • 使用容器时,迭代器很长。
  • 匿名函数返回值。
  • 模板函数中使用auto,节约模板参数类型。

5.4 decltype

5.4.1 原理

  • decltype用于推导表达式的类型,只分析表达式而不参与运算。

5.4.2 规则

  • exp是一个普通的表达式,推导表达式类型。
  • exp是函数调用,推导函数返回值类型。
  • exp是一个左值,推导左值引用。

5.4.3 应用

  • 泛型编程

6 function,lambda和bind

  • function:类模板。
  • lambda:表达式。
  • bind:函数适配器。

6.1 function

C++11以前,保存函数地址用的是和C语言一样的方式—函数指针。于是C++11就引入了std::function类模板。

6.1.1 function是什么

  • function是一个抽象了函数参数以及函数返回值的一个类模板。

6.1.2 function原理

  • function把任意函数包装成一个对象,该对象可以保存,传递以及复制。
  • 动态绑定,只需修改改对象(赋值不同的function对象),实现类似多态的效果。

6.1.3 function用途

  • 保存普通函数,类的静态成员函数。
  • 保存仿函数(函数对象)。
  • 保存类的成员函数。
  • 保存lambda表达式。
  • 保存bind返回的函数对象。

6.2 仿函数(函数对象)

6.2.1 仿函数是什么

  • 重载了operator()的类。

6.2.2 仿函数的特征

  • 可以有状态(成员变量存储状态)。
  • 有状态的函数称之为闭包。

6.3 lambda表达式

6.3.1 lambda表达式是什么

  • 一种方便创建匿名函数对象的语法糖。

6.3.2 lambda的构成

  • []:捕获列表。捕获外部变量转为类的成员变量。
  • 值捕获:访问匿名函数的外部变量,默认只读,不能修改,使用mutable可以可读可写,这样就不会修改外部变量的值。
  • 引用捕获:可读可写,会修改外部变量的值。
  • ():参数列表。
  • ->:指定返回值。可省略,有类型推导。
  • {}:函数的具体实现。

6.3.3 lambda原理

  • 将lambda表达式转变为一个函数对象。
  • 将lambda的参数列表重载operator(),类似仿函数。

6.4 bind函数适配器

6.4.1 bind函数适配器是什么

  • 用来通过绑定函数以及函数参数的方式生成函数对象的模板函数。
  • 提供占位符,实现灵活的参数绑定。

6.4.2 bind函数适配器的特征

  • 绑定函数以及函数参数,从而构成一个函数对象
  • 允许修改参数顺序

  • 函数对象是一个闭包
  • function是用来描述函数对象的类型。
  • lambda是生成一个能访问外部变量的函数对象。
  • bind是生成一个能够和参数函数对象。

7 继承下的构造函数和析构函数的执行顺序

  • 构造:按照依赖链,越强越先。
  • 析构:按照依赖链,越弱越先。

单继承中:

  • 成员类按顺序构造,按相反顺序析构。
  • 类的构造依赖成员类的构造。
  • 基类比成员类依赖性更强。

多继承中:

  • 成员类按顺序构造,按相反顺序析构。
  • 类的构造依赖成员类的构造。
  • 基类比成员类依赖性更强。
  • 基类按照声明顺序构造,按相反顺序析构。

8 虚函数表和虚函数表指针的创建时机

先产生虚函数表,每个对象都有虚函数表指针。

8.1 虚函数表的创建时机

  • 编译器发现类中包含virtual关键字修饰的函数。
  • 虚函数表的内容在编译器编译的时候就已经生成了。
  • 虚函数表存放在全局数据区中的只读数据段中。
  • 虚函数表是存放虚函数地址的数组。

8.2 虚函数表指针的创建时机

  • 对象构造的时候,在构造函数,将虚函数表的地址赋值给对象的虚函数指针。
  • 如果类没有构造函数,编译器会为该类自动生成一个默认构造函数,从而为类对象初始化虚函数指针。

继承下,虚函数表指针赋值过程:

  • 调用基类构造函数时,先将基类的虚函数表指针地址赋值给vptr。
  • 接着调用子类的构造函数时,将子类的虚函数表地址赋值给vptr。也就是覆盖上面一步的vptr。

9 虚析构函数

  • 作用:在继承下,为了使子类析构函数能够得到正常调用,需要将基类的析构函数设置为虚析构函数。
  • 场景:子类对象指针赋值给基类指针,在调用析构函数时,子类的析构函数不会被调用。
  • 在C++看来,设计某个类的时候,不一定是基类
  • 如果是基类,我们应该手动的将基类的析构函数设置为虚函数。

10 智能指针种类以及使用场景

10.1 指针管理的困境

  • 资源释放了,指针没有置空。野指针:只有一个指针指向资源。指针悬挂:多个指针指向同一个资源。踩内存。
  • 资源忘记释放了。
  • 重复释放资源。

10.2 解决

智能指针采用RAII思想来自动化管理指针所指向的动态资源的释放。

RAII主要利用了对象的生命周期来控制程序资源。

智能指针利用类的构造函数和析构函数来管理资源。

10.3 智能指针的种类

10.3.1 shared_ptr

解决指针悬挂问题。

  • 语义:共享所有权。资源没有明确的拥有者。
  • 原理:引用技术。
  • 场景:容器中管理指针。资源通过函数传递。
  • 使用规范:不要使用原来的裸指针—构造智能指针时,不要暴露裸指针。尽量使用make_shared来构造智能指针。不要通过get来操作裸指针。不要用一个指针构造多个智能指针对象。不要用类对象this作为shared_ptr返回。

10.3.2 weak_ptr

  • 辅助shared_ptr,解决shared_ptr出现的循环引用的问题。
  • 原因是弱引用不占用强引用计数。

10.3.3 unique_ptr

解决指针悬挂问题。

  • 语义:独享所有权。没有赋值运算操作符。仅提供移动构造和移动赋值。
  • 明确某个对象只有一个拥有者。
  • 场景:
  • 使用规范:不支持拷贝,但是可以从函数中返回一个unique_ptr,编译器优化可以解决。make_unique C++14提供的。

 

 

 

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

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

相关文章

用HTML5 Canvas创造视觉盛宴——动态彩色线条效果

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- 声明文档类型为XHTML 1.0 Transitional -…

Python四级考试笔记

Python四级考试笔记【源源老师】 四级标准 一、 理解函数及过程、函数的参数、函数的返回值、变量作用域等概念。 二、 能够创建简单的自定义函数。 三、 理解算法以及算法性能、效率的概念&#xff0c;初步认识算法优化 效率的方法。 四、 理解基本算法中递归的概念。 五、 掌…

C语言---自幂数(“水仙花数”)

1.打印0~100000的自幂数 #include<stdio.h> #include<math.h> int main() {int i 0; for (i 0; i<100000; i){int n 0;int temp i;//判断位数while (temp){n;temp temp / 10;}//每个数字求和temp i;int sum 0;while (temp){sum sum pow(temp % 10, n)…

[office] 如何固定excel单元格的方法 #笔记#微信#微信

如何固定excel单元格的方法 在Excel中录入好数据以后就需要进行统计数据&#xff0c;在有些单元格中的数据不能够改变位置&#xff0c;因此我们需要对特定的单元格进行锁定固定。下面是由小编分享的如何固定excel单元格的方法&#xff0c;供大家阅读、学习。 如何固定excel单元…

掘根宝典之C++多重继承,二义性,虚基类

多重继承派生类 除去一个类从一个基类派生&#xff0c;C还支持一个派生类同时继承多个基类 MI&#xff1a;有多个直接基类的类 1.多重继承派生类的定义 如果已经定义了多个基类&#xff0c;那么定义多重继承的派生类的形式为&#xff1a; class 派生类名:访问标号1 基类名…

【开源】SpringBoot框架开发独居老人物资配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询社区4.2 新增物资4.3 查询物资4.4 查询物资配送4.5 新增物资配送 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的独居老人物资配送系统&#xff0c;包含了社区档案、…

win7自带截图工具保存失效解决办法

今日发现一台远航技术的win7中自带的截图工具使用时正常&#xff0c;保存图片时没有弹出保存位置的对话窗口&#xff0c;无法正常保存图片。解决方案如下&#xff1a; 1、进入注册表编辑器。开始-搜索程序和文件-输入 regedit 按下回车键&#xff0c;打开注册表&#xff1b; 2、…

多模态基础---BERT

1. BERT简介 BERT用于将一个输入的句子转换为word_embedding&#xff0c;本质上是多个Transformer的Encoder堆叠在一起。 其中单个Transformer Encoder结构如下&#xff1a; BERT-Base采用了12个Transformer Encoder。 BERT-large采用了24个Transformer Encoder。 2. BERT的…

360小工具

有时候不希望打开360安全卫士&#xff0c;但又需要使用它的小工具 小工具目录统一基于360安装目录&#xff0c;一般情况在&#xff1a;C:\Program Files (x86)\360\360Safe 备份还原小工具 C:\Program Files (x86)\360\360Safe\Utils\winrebackup\360WinREBackup64.exe 360LS…

静态时序分析:SDC约束命令set_clock_transition详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在静态时序分析&#xff1a;SDC约束命令create_clock详解一文的最后&#xff0c;我们谈到了针对理想(ideal)时钟&#xff0c;可以使用set_clock_transition命令直…

MQTT的应用场景和发展方向

随着物联网&#xff08;IoT&#xff09;技术的发展&#xff0c;MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为一种轻量级的通信协议&#xff0c;正在被广泛应用于各种物联网场景中。本文将介绍MQTT的应用场景以及未来的发展方向。 一、MQTT的应用场景…

在Linux系统中,yum 和 apt-get 都是用于管理软件包和更新系统的命令行工具,它们的区别是什么?

一、 yum yum 是在基于RPM的Linux发行版&#xff08;如CentOS、RHEL及其衍生版&#xff09;中使用的包管理器。它通过网络连接到软件仓库并自动处理依赖关系来安装、更新和卸载软件包。主要命令包括&#xff1a; 1、更新软件包列表 yum update 2、安装软件包 yum install …

c++堆排序解释

堆排序是一种基于二叉堆数据结构的排序算法。它是利用了堆的性质&#xff0c;即父节点的值总是大于或等于&#xff08;或小于或等于&#xff09;其子节点的值。 堆排序的基本思想是首先将待排序的数组构建成一个最大堆&#xff08;或最小堆&#xff09;&#xff0c;然后将堆的…

数据结构与算法:双向链表

朋友们大家好啊&#xff0c;在上节完成单链表的讲解后&#xff0c;我们本篇文章来对带头循环双向链表进行讲解 双向链表 双向链表、头节点和循环的介绍构建双向链表节点的构建初始化双向循环链表&#xff08;空链表&#xff09;销毁双向链表 链表的打印双向链表头尾的插与删尾插…

Medical Boundary Diffusion Modelfor Skin Lesion Segmentation

皮肤病灶分割的医学边界扩散模型 摘要 由于多尺度边界关注和特征增强模块的进步&#xff0c;皮肤镜图像中的皮肤病变分割最近取得了成功。然而&#xff0c;现有的方法依赖于端到端学习范式&#xff0c;直接输入图像和输出分割图&#xff0c;经常与极其困难的边界作斗争&#…

B端系统升级方案模板:针对美观性和体验性升级(总体方案)

大家好&#xff0c;我是大美B端工场&#xff0c;专注于前端开发和UI设计&#xff0c;有需求可以私信。本篇从全局分享如何升级B端系统&#xff0c;搞B端系统升级的有个整体思维&#xff0c;不是说美化几个图标&#xff0c;修改几个页面就能解决的&#xff0c;这个方案模板&…

laravel_进程门面_再次介绍

文章目录 单次调用进程池调用伪造和断言断言和判断的区别 前面我已经简单介绍了一点process facades&#xff0c;这里再进行一个补充的介绍。 可以也看看前面的介绍。 单次调用 use Illuminate\Support\Facades\Process;$result Process::run(ls -la);return $result->ou…

c++希尔排序解释

希尔排序是一种排序算法&#xff0c;它是插入排序的改进版本。它通过将序列分成多个子序列&#xff0c;对每个子序列进行插入排序&#xff0c;然后逐步减小子序列的长度&#xff0c;直到整个序列有序。 希尔排序的基本思想是&#xff1a;选择一个增量序列&#xff0c;根据增量…

【天枢系列 01】Linux行数统计:命令对决,谁才是王者?

文章目录 01 统计行数命令1.1 wc 命令1.2 grep 命令1.3 sed 命令1.4 awk 命令1.5 Perl 命令 02 Linux的wc命令详细用法2.1 基本语法2.2 主要选项2.3 附加选项2.4 示例用法2.5 注意事项【重要&#xff01;】 03 Linux的grep命令详细用法3.1 基本语法3.2 主要选项3.3 示例用法3.4…

Spring AMQP(3.1.1)设置ConfirmCallback和ReturnsCallback

文章目录 一、起因二、代码1. 定义exchange和queue2. RabbitTemplate3. EnhancedCorrelationData4. 发送消息 环境如下 VersionSpringBoot3.2.1spring-amqp3.1.1RabbitMq3-management 一、起因 老版本的spring-amqp在CorrelationData上设置ConfirmCallback。但是今天却突然发…