当前位置: 首页 > news >正文

【面试】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的例子解释

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

排序的思路,代码实现

深浅拷贝

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

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

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

相关文章:

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

C/C面试八股 编译过程的四个阶段C和C语言的区别简单介绍一下三大特性多态的实现原理虚函数的构成原理虚函数的调用原理虚表指针在什么地方进行初始化的&#xff1f;构造函数为什么不能是虚函数为什么建议将析构函数设为虚函数虚函数和纯虚函数的区别抽象类类对象的对象模型内存…...

学习记忆——数学篇——算术——无理数

谐音记忆法 2 \sqrt{2} 2 ​≈1.41421&#xff1a;意思意思而已&#xff1b;意思意思&#xff1b; 3 \sqrt{3} 3 ​≈1.7320&#xff1a;—起生鹅蛋&#xff1b;一起生儿&#xff1b; 5 \sqrt{5} 5 ​≈2.2360679&#xff1a;两鹅生六蛋(送)六妻舅&#xff1b;儿儿生&#xf…...

python协程和任务

协程概念引入 ​ 协程是我要重点去讲解的一个知识点. 它能够更加高效的利用CPU. ​ 其实, 我们能够高效的利用多线程来完成爬虫其实已经很6了. 但是, 从某种角度讲, 线程的执行效率真的就无敌了么? 我们真的充分的利用CPU资源了么? 非也~ 比如, 我们来看下面这个例子. 我们…...

visual studio code配置anaconda3的python虚拟环境

参考&#xff1a; Visual Studio Code配置anconda3虚拟环境 - 知乎...

【Unity3D编辑器开发】Unity3D编辑器开发基础性框架结构【全面总结】

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 嗨&#xff0c;大家好&#xff0c;我是恬静的小魔龙。 同学们…...

一座“城池”:泡泡玛特主题乐园背后,IP梦想照亮现实

“更适合中国宝宝体质”的主题乐园&#xff0c;被泡泡玛特造出来了。 9月26日&#xff0c;位于北京朝阳公园内的国内首个潮玩行业沉浸式 IP 主题乐园&#xff0c;也是泡泡玛特首个线下乐园——泡泡玛特城市乐园 POP LAND正式开园。 约4万平方米的空间中&#xff0c;泡泡玛特使…...

【什么是闭包? 闭包产生的原因? 闭包有哪些表现形式?】

JS闭包 什么是闭包&#xff1f;闭包产生的原因?闭包有哪些表现形式? 什么是闭包&#xff1f; 闭包是指一个函数可以访问并操作在其作用域之外的变量的能力。在 JavaScript 中&#xff0c;每当函数被创建时&#xff0c;就会创建一个闭包。 以下是一个简单的闭包示例&#xf…...

JackJson和FastJson

前言&#xff1a; fastjson是一款强大的json格式转换工具&#xff0c;我个人在开发中就非常喜欢用fastjson&#xff1b;但是由于某些原因&#xff0c;导致fastjson会有一些漏洞&#xff0c;因此在漏洞扫描后需要修复都是要求我们升级版本&#xff0c;或者替换为jackjson&#…...

SpringCloud学习一

单体应用存在的问题 随着业务的发展&#xff0c;开发变得越来越复杂。 修改、新增某个功能&#xff0c;需要对整个系统进行测试、重新部署。 一个模块出现问题&#xff0c;很可能导致整个系统崩溃。 多个开发团队同时对数据进行管理&#xff0c;容易产生安全漏洞。 各个模块…...

SpringBoot, EventListener事件监听的使用

1、背景 在开发工作中&#xff0c;会遇到一种场景&#xff0c;做完某一件事情以后&#xff0c;需要广播一些消息或者通知&#xff0c;告诉其他的模块进行一些事件处理&#xff0c;一般来说&#xff0c;可以一个一个发送请求去通知&#xff0c;但是有一种更好的方式&#xff0c;…...

课题学习(三)----倾角和方位角的动态测量方法(基于陀螺仪的测量系统)

一、内容介绍 该测量系统基于三轴加速度和三轴陀螺仪&#xff0c;安装在钻柱内部&#xff0c;随钻柱一起旋转&#xff0c;形成捷联惯性导航系统&#xff0c;安装如下图所示&#xff1a;   假设三轴加速度和陀螺仪的输出为: f b [ f x f y f z ] T f^b\begin{bmatrix}f_{x} …...

1876. 长度为三且各字符不同的子字符串

1876. 长度为三且各字符不同的子字符串 C代码&#xff1a;滑动窗口 // 存在三种字符&#xff0c;且不重复、子串数量 int countGoodSubstrings(char * s){int k 3;int hash[26] {0};int len 0;int l 0;int ans 0;for (int i 0; i < strlen(s); i) {hash[s[i] - a];if…...

Mall脚手架总结(一)——SpringSecurity实现鉴权认证

前言 在结束理论知识的学习后&#xff0c;荔枝开始项目学习&#xff0c;这个系列文章将围绕荔枝学习mall项目过程中总结的知识点来梳理。本篇文章主要涉及如何整合Spring Security和JWT实现鉴权认证的功能&#xff01;希望能帮助到一起学习mall项目的小伙伴~~~ 文章目录 前言 …...

beego-简单项目写法--路径已经放进去了

Beego案例-新闻发布系统 1.注册 后台代码和昨天案例代码一致。,所以这里面只写一个注册的业务流程图。 **业务流程图 ** 2.登陆 业务流程图 登陆和注册业务和我们昨天登陆和注册基本一样&#xff0c;所以就不再重复写这个代码 但是我们遇到的问题是如何做代码的迁移&…...

Linux-CPU相关常用命令合集

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、cpu相关常用命令 二、cpuinfo 参数详细对照表 前言 本篇文章主要记录平时Linux-常用命令整理&#xff01; 提示&#xff1a;以下是本篇文章正文内容&#…...

vue 百度地图/天地图设置铺满屏幕100%,解决空隙问题

设置100%无效&#xff0c;刷新依然右侧有空隙&#xff0c;解决&#xff1a;min-width: 100vw; <div class"aui-flex-col" style"width: 100%; height:100%"><div id"mapAllCon" style"width: 100%; min-width: 100vw; height: 10…...

2023年安全员安徽题库,精准题库,历年真题,模拟试题

...

第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第六节 - Python 中字符串的逻辑运算符)

对于 python 中的字符串,布尔运算符(and、or、not)起作用。让我们考虑两个字符串,即 str1 和 str2,并在它们上尝试布尔运算符: Python3 str1 = str2 = geeks# 使用 repr 打印带引号的字符串# 返回 str1 print(repr(str1 and str2)) # 返回 str1 print(repr(str2 and…...

Bark Ai 文本转语音 模型缓存位置修改

默认缓存位置在&#xff1a;~/.cache 加入环境变量&#xff1a;XDG_CACHE_HOME&#xff0c;指定缓存位置 修改后新的位置为&#xff1a; D:\Ai\Bark\Bark Cache...

Docker 镜像的创建

目录 一、Docker镜像的创建 1、基于已有镜像创建 2、基于本地模板创建 3、基于dockerfile创建 3.1 dockerfile结构 3.2 构建镜像命令 二、镜像分层的原理 1、联合文件系统&#xff08;UnionFS&#xff09; 2、镜像加载的原理 三、Dockerfile 操作常用的指令 案例实验…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...