【面试】C/C++面试八股

C/C++面试八股

  • 编译过程的四个阶段
  • C++和C语言的区别
  • 简单介绍一下三大特性
  • 多态的实现原理
  • 虚函数的构成原理
  • 虚函数的调用原理
  • 虚表指针在什么地方进行初始化的?
  • 构造函数为什么不能是虚函数
  • 为什么建议将析构函数设为虚函数
  • 虚函数和纯虚函数的区别
  • 抽象类
  • 类对象的对象模型
  • 内存分布方式?
  • 内存对齐是什么?为什么要内存对齐
  • static关键字的作用
  • const关键字的作用
  • 内联函数与宏函数区别
  • 指针和引用的区别
  • 介绍一下vector的扩容过程
  • vector如何释放内存空间
  • map与unordered_map的区别
  • 对于插入来说,operator[]与insert的区别
  • 对于访问来说,operator[]与.at的区别
  • new和malloc的区别
  • new的实现原理
  • operator new的原理
  • malloc的实现原理
  • 内存泄露的检测工具
  • 特殊类的设计
  • C++11的锁有哪些
  • C++11的智能指针
  • 几种排序的思路,代码实现
  • 深浅拷贝

编译过程的四个阶段

一、预处理
头文件展开,宏替换,去注释,条件编译
二、编译
语法词法分析,将源代码转化为汇编指令
三、汇编
将汇编指令转换为二进制的机器指令
四、链接
用目标文件+库文件生成可执行文件

C++和C语言的区别

一.C++解决了很多C语言固有的缺陷:

  1. 针对C语言中存在命名冲突,C++提供了命名空间来解决
    2.C语言不支持函数缺省参数,C++也提供了缺省参数的方法
    3.在C语言中,由于宏函数的有效性无法检查,所以C++提出了内联函数解决

二.在C语言指针的基础上,C++提出了引用

三.C++可以实现函数重载,原因是C语言对于函数的区分是用函数名来区分的,而C++是使用函数名+函数参数列表来区分的,因此C语言中,只要函数名称一致,就会导致编译器报错,而C++中,可以设置函数名称一致,而参数列表不同的函数,作为函数的重载形式
四.C语言采用的是面向过程的编程思想,专注于过程。而C++采用的是面向对象的编程思想,关注的是对象,靠对象之间的交互完成
五.C语言的结构体中只能定义变量,而C++的类中,既可以定义变量也可以定义函数

简单介绍一下三大特性

封装:就是将数据和对数据的操作方式结合起来,隐藏细节,对外暴露一些接口,以供对象之间进行交互,本质上是为了让用户更好的管理类

继承:是一种代码的复用手段,目的是在原有类的基础上进行扩展,增加新的功能,生成新的类

多态:就是多种形态,当完成某个动作时,不同的对象去完成,产生不同的状态
多态可以分为静态多态和动态多态
静态多态是在程序编译阶段就确定了函数的执行动作,典型例子是:函数重载。
动态多态是在程序运行时通过传递的对象实际类型来确定函数的执行,典型例子是:函数的重写

多态的实现原理

多态的实现条件
1.需要首先让派生类重写基类的虚函数
2.通过基类的指针或引用来调用虚函数

多态的实现原理:
某个类成员函数被virtual修饰之后,该类的对象模型中就会有一个虚表指针,这个指针指向一个虚表,该虚表中就会存放虚函数地址。
当某个派生类将该基类继承之后,该派生类的对象模型中也会有一个和基类中一致的虚表指针,如果这个派生类将基类中的虚函数进行了重写,那么自己的虚表中就会将原来基类虚表中对应的虚函数指针替换
此时如果我们使用基类的指针或引用去调用虚函数,那么如果传递的是基类对象,那么就会通过this指针去调用基类对象的成员函数,如果传递的是子类对象,那么就会通过this指针去调用子类对象的成员函数。

虚函数的构成原理

在编译阶段,将虚函数按照在类中的声明次序依次添加到虚表中

在单继承体系下,子类虚表的构建原理:
1、原封不动将基类虚表中的内容拷贝一份到子类虚表中
2、如果子类中哪个函数重写了基类虚表中的虚函数,则将虚表中对应的虚函数指针替换为当前重写后的虚函数指针
3、将子类新增的虚函数按照在子类中声明的次序进行添加

虚函数的调用原理

通过实际传入的对象的this指针,拿到对应的虚表指针,再通过对应的虚表指针,找到对应的虚表,然后通过虚表中存放的虚函数地址,来进行虚函数的调用。

包含有虚函数的类对象,编译器在编译时,就为该对象创建了一个虚表指针,以便于能够正确的获取该类的虚表

虚表指针在什么地方进行初始化的?

在构造函数中,进行虚表的创建和虚表指针的初始化

构造函数为什么不能是虚函数

因为虚函数对应一个虚表指针,这个虚表指针是存储在对象的内存空间的,构造函数就是用来去开辟对象的内存空间 的,如果构造函数是虚函数,意味着在对象内存空间还不存在的就要去初始化对象内存空间中的值,是无法实现的

为什么建议将析构函数设为虚函数

如果没有将析构函数设为虚函数,那么当传递的是子类对象,而我们是用基类对象的指针或引用去接收时,会导致无法调用子类对象的析构函数,从而导致内存泄漏

虚函数和纯虚函数的区别

虚函数目的是建立抽象模型,方便系统扩展
纯虚函数是不具体实现的函数,一种特殊的函数

虚函数必须是类的非静态成员

纯虚函数是虚函数的子集,用于抽象类,包含有纯虚函数的类是抽象类,不能实例化对象
因为有时候基类实例化对象是不合理的,例如:基类是动物,子类是猫狗,那么基类本身可以创建对象就是不合理的,那么用纯虚函数修饰之后,让基类无法创建对象才是较为合理的

抽象类

包含纯虚函数的类就是抽象类
抽象类不能实例化对象,只能在该类被派生之后,并且所有的纯虚函数都被重写之后,才能被创建对象

类对象的对象模型

类对象中只存储了类的成员变量,并且按照成员变量的声明顺序进行存储,遵循内存对齐原则,如果存在虚函数,那么会有虚表指针,如果存在虚拟继承,那么还会有一个虚基表指针。
在继承体系下,如果是普通的继承,那么子类对象的对象模型是:
首先是基类继承,然后是子类新增
在这里插入图片描述

如果是虚拟继承:
继承自多个基类,那么按照派生类的声明顺序进行。
每个来自基类的对象模型中,只存储一个虚基表指针,指向各自基类对应位置
然后是子类新增,最后是基类成员变量
在这里插入图片描述

内存分布方式?

由高地址到低地址分别为:

栈区,共享区,堆区,全局区,常量区,代码区

栈区:由高地址向低地址生长,存储函数调用的临时信息,局部变量等

共享区:共享内存通过页表映射到不同的进程虚拟地址空间中

堆区:由低地址向高地址生长,由程序员调用malloc或new申请的空间

全局区:分为BSS段和数据段,BSS段为未初始化的全局或者静态变量,数据段为已经初始化的全局或者静态变量

常量区:存放常量字符串,程序结束后由系统释放

代码段:存放类的成员函数,静态函数和全局函数的二进制代码

内存对齐是什么?为什么要内存对齐

1、提高内存访问效率
2、减小内存占用量

static关键字的作用

static关键字的作用: static关键字的作用

const关键字的作用

const关键字的作用:const关键字的作用

内联函数与宏函数区别

内联函数:在函数定义位置前用inline修饰,在编译阶段会将内联函数进行展开
宏函数(宏定义):在函数定义前用#define修饰,在预处理阶段就会对宏函数进行展开

#define fun1() cout << "a" << endlinline void fun2()
{cout << "a" << endl;
}
int main()
{//宏函数是在预处理阶段会将fun1() ----> cout << "a" << endlfun1();//在编译阶段会直接将fun2()  --->  cout << "a" << endl;fun2();return 0;
}

宏函数的优点:
提高性能,增加代码复用性
宏函数的缺点:
不方便调试,可读性差,没有类型安全的检查

改进方式:常量----->const修饰,函数------>内联函数

指针和引用的区别

1.指针存储的是地址,而引用是对变量的一个别名
2.引用在定义时必须初始化,而指针不用
3.指针可以通过修改值来改变指针的指向,引用关系一旦确立,引用的实体就不能改变了
4.sizeof时,传递的是指针,计算的是指针占空间的大小,引用是变量类型的大小
5.指针需要显式解引用,引用不用
6.存在空置指针,而不存在空值引用

介绍一下vector的扩容过程

vector如何释放内存空间

map与unordered_map的区别

1.map的底层是红黑树,unordered_map底层是哈希表
2.map是按照key有序的,unordered_map无序
3.map的查询效率是O(logn),unordered_map是O(1)
4.map更适合需要数据有序,对查询效率不是那么高的场景,unordered_map适合对查询效率极高的场景

对于插入来说,operator[]与insert的区别

如果key存在,那么都会插入失败,但是operator[]会将原来的key对应的value替换为新的value,而insert不进行任何操作
如果key不存在,那么都会插入成功,通过key和value构造键值对,进行插入

operator[]底层调用的是insert,insert返回的是对应位置的迭代器,operator[]拿到返回的迭代器,返回的是key对应的value

对于访问来说,operator[]与.at的区别

如果key存在,operator[]和.at()一样会返回key对应的value
如果key不存在,operator[]会key和默认的value构成键值对,插入map中

new和malloc的区别

1.new是关键字,malloc是库函数
2.new申请空间失败会抛异常,malloc不会
3.new只需要传递类型,编译器会根据类型判断申请空间大小,malloc需要手动传递字节数
4.new申请空间之后不需要进行类型转换,malloc需要
5.new在申请空间之后还会调用构造函数进行对象的构造,而malloc不会,同理delete会自动调用析构函数,而free不会

new的实现原理

1、调用operator new()函数申请空间
2、在申请的空间上执行构造函数,完成对象的构造

operator new的原理

1、调用malloc函数申请空间
2、如果申请成功,返回空间地址,如果申请失败,会执行用户定义的方法,继续申请空间,如果用户没有定义申请失败的方法,那么就会抛异常

malloc的实现原理

1、内存管理:内存管理的数据结构是一个链表, 每个节点表示的是一个内存块,调用malloc时,先遍历该链表找到一块足够大的内存块,标记为已分配状态
2、内存分配,将已分配的内存块首地址返回给程序

内存泄露的检测工具

在linux下进行内存泄漏的检测工具:valgrind
在win下的内存泄漏检测工具:VLD

特殊类的设计

设计类不能被继承:将构造函数私有化
设计类不能被拷贝:将拷贝构造和赋值运算符重载只声明不定义
设计类只能从堆上创建对象:
方法一:将构造函数和拷贝构造函数私有化,设置一个静态成员函数,函数内通过new创建对象,返回对象指针
设计类只能从栈上创建对象:
方法一:将构造函数私有化,将operator new()禁掉
方法二:将构造函数和拷贝构造函数私有化,设置一个静态成员函数,在该函数中调用构造函数,返回对象

设计一个单例类:
饿汉模式:将构造拷贝构造赋值运算符都私有化,类内声明一个私有的静态类对象和一个公有的静态成员函数,在函数内对静态类对象进行初始化,返回对象指针

懒汉模式:将构造函数和拷贝构造函数和赋值运算符重载都私有化,类内声明一个私有的静态类对象指针和一个公有的静态成员函数,在函数中new一个对象的指针赋值给该静态对象指针。需要注意的是double chack

C++11的锁有哪些

六大种:
1、mutex
2、recursive_mutex
3、timed_mutex
4、recursive_timed_mutex
5、lock_guard:对mutex进行封装,实现了RAII,可以预防死锁
6、unique_lock:在lock_guard上增加了加锁解锁查看锁状态等功能

C++11的智能指针

auto_ptr:已资源管理权限转移的方式解决浅拷贝,弃用,容易造成野指针

unique_ptr:已资源独占的方式解决浅拷贝,无法拷贝,不方便

shared_ptr:已资源计数的方式解决浅拷贝,容易造成循环引用的问题,解决方式是weak_ptr,用ListNode的例子解释

几种排序的思路,代码实现

排序的思路,代码实现

深浅拷贝

在一个类中,如果没有显式定义拷贝构造函数或者赋值运算符重载,编译器自动生成的拷贝构造函数和赋值运算符重载函数就是浅拷贝。

浅拷贝: 复制对象的过程中,仅复制对象的成员变量的值,不复制指向的动态内存,多个对象可能共用一份数据

深拷贝:复制对象的过程中,不仅复制对象的成员变量的值,还复制指向的动态内存,创建独立的副本

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

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

相关文章

用 Pytest+Allure 生成漂亮的 HTML 图形化测试报告

本篇文章将介绍如何使用开源的测试报告生成框架 Allure 生成规范、格式统一、美观的测试报告。 通过这篇文章的介绍&#xff0c;你将能够&#xff1a; 将 Allure 与 Pytest 测试框架相结合&#xff1b; 如何定制化测试报告内容 执行测试之后&#xff0c;生成 Allure 格式的测…

AutoGen - 多个Agent开发LLM应用的框架

文章目录 关于安装使用关于 Enable Next-Gen Large Language Model Applications 用多个Agent开发LLM应用的框架,这些agent可相互交流以解决任务。 官网:https://microsoft.github.io/autogen/github : http://github.com/microsoft/autogendiscord : https://discord.com/i…

面试官必问的分布式锁面试题,你答得上来吗?

一、面试聊聊-分布式锁&#xff0c;如何回答&#xff1f; 要分析分布式锁这个问题&#xff0c;我们根据黄金圈法则来分析 黄金圈法则是由美国营销顾问西蒙斯涅克&#xff08;Simon Sinek&#xff09;提出的一种思维模型&#xff0c;用于帮助人们更好地理解和传达信息。黄金圈法…

自定义类型:结构体,枚举,联合

目录 前言 一、结构体 1.构体的声明 1.1 结构的基础知识 1.2 结构的声明 1.3 特殊的声明 1.4 结构的自引用 1.5 结构体变量的定义和初始化 1.6 结构体内存对齐 1.7 修改默认对齐数 2. 位段 2.1 什么是位段 2.2 位段的内存分配 2.3 位段的跨平台问题 2.4 位段的应…

网络基础知识面试题1

VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)

Spring-事务管理-加强

目录 开启事务 编程式事务 声明式事务 声明式事务的优点 声明式事务的粒度问题 声明式事务用不对容易失效 Spring事务失效可能是哪些原因 Transactional(rollbackFor Exception.class)注解 Spring 事务的实现原理 事务传播机制 介绍 用法 rollbackFor 场景举例 …

深入探究C++编程中的资源泄漏问题

目录 1、GDI对象泄漏 1.1、何为GDI资源泄漏&#xff1f; 1.2、使用GDIView工具排查GDI对象泄漏 1.3、有时可能需要结合其他方法去排查 1.4、如何保证没有GDI对象泄漏&#xff1f; 2、进程句柄泄漏 2.1、何为进程句柄泄漏&#xff1f; 2.2、创建线程时的线程句柄泄漏 …

CleanMyMacX 永久版下载激活码破解版

CleanMyMac X最新破解版V4.9.2是一款出色的Mac 系统垃圾清理程序。 该软件具有强大的垃圾清理功能&#xff0c;可以释放数 GB 的空间&#xff0c;让您的 Mac 焕然一新。 带有激活码的完整破解版 CleanmyMac 可加速您的 Mac 设备。 此外&#xff0c;cleanmymac还能帮助您从 Mac…

小谈设计模式(17)—状态模式

小谈设计模式&#xff08;17&#xff09;—状态模式 专栏介绍专栏地址专栏介绍 状态模式关键角色上下文(Context)抽象状态(State)具体状态(Concrete State) 核心思想Java程序实现首先&#xff0c;我们定义一个抽象状态类 State&#xff0c;其中包含一个处理请求的方法 handleRe…

Centos7 安装mysql 8.0.34并设置不区分大小写

索引 Centos7 安装mysql 8.0.34准备工作安装教程安装并配置配置MySQL配置远程访问重新启动MySQL服务 为已安装的MySQL8设置不区分大小写背景操作步骤 Centos7 安装mysql 8.0.34 准备工作 centos7 服务器 xshell 安装教程 安装并配置 在安装MySQL之前&#xff0c;我们应该…

【无标题】This project has been opened by another efinity instance

This project has been opened by another efinity instance 说明&#xff1a;&#xff08;1&#xff09;软件自动即出可能有些进程没有关闭 &#xff08;2&#xff09;目录中有中文路径。

POJ 2104 K-th Number 平方分割 / 线段树

一、题目大意 长度为n&#xff08;n<100000&#xff09;的数组&#xff0c;进行m次查询&#xff08;m<5000&#xff09;&#xff0c;每次查询时&#xff0c;输入为 i j k&#xff0c;返回为数组 [i,j] 的分片里第k大数字&#xff08;1<i<j<n,k<j-i1) 二、解…

vue3 中使用echarts图表——柱状图

柱状图是比较常用的图形结构&#xff0c;所以我先收集一些精美的柱状图 一、柱状图&#xff1a;设置圆角和颜色 <template><div class"box" ref"chartDom"></div> </template> <script setup> import { ref, onMounted } fr…

力扣第100题 相同的数 c++ 二叉 简单易懂+注释

题目 100. 相同的树 简单 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出…

RabbitMQ之Direct(直连)Exchange解读

目录 基本介绍 使用场景 springboot代码演示 演示架构 工程概述 RabbitConfig配置类&#xff1a;创建队列及交换机并进行绑定 MessageService业务类&#xff1a;发送消息及接收消息 主启动类RabbitMq01Application&#xff1a;实现ApplicationRunner接口 基本介绍 在r…

功能测试复习

一。测试流程 1.需求评审 确保各部门需求理解一致 2.计划编写 测什么&#xff0c;谁来测&#xff0c;怎么测 3.用例设计 验证项目是否符合需求的操作文档 4.用例执行 项目模块开发完成开始执行用例文档实施测试 5.缺陷管理 对缺陷进行…

[晕事]今天做了件晕事21;设置代理访问网站的时候需注意的问题

今天在家上班&#xff0c;设置好VPN&#xff0c;通过代理来访问公司内部的一个系统浏览器的反应如下&#xff1a; Hmmm… can’t reach this page ***.com refused to connect. 这个返回的错误&#xff0c;非常的具有迷惑性&#xff0c;提示的意思&#xff1a;拒绝链接&#xf…

李沐深度学习记录2:10多层感知机

一.简要知识记录 x.numel()&#xff1a;看向量或矩阵里元素个数 A.sum()&#xff1a;向量或矩阵求和&#xff0c;axis参数可对某维度求和&#xff0c;keepdims参数设置是否保持维度不变 A.cumsum&#xff1a;axis参数设置沿某一维度计算矩阵累计和x*y:向量的按元素乘法 torch.…

时间序列常用数据处理

1.组合技巧Compose 1.2 实例应用及其解释 # 用于组合多个数据处理方法 class Compose(object):def __init__(self, transforms):self.transforms transformsdef __call__(self, seq):for t in self.transforms:seq t(seq)return seq 这段Python代码定义了一个名为Compose的…

【Spring Boot】日志文件

日志文件 一. 日志文件有什么用二. 日志怎么用三. ⾃定义⽇志打印1. 在程序中得到⽇志对象2. 使⽤⽇志对象打印⽇志3. ⽇志格式说明 四. 日志级别1. ⽇志级别有什么⽤2. ⽇志级别的分类与使⽤ 五. 日志持久化六. 更简单的⽇志输出—lombok1. 添加 lombok 依赖2. 输出⽇志3. lom…