腾讯C++实习生常见面试题(含每道题详细答案)
我目前是大三一名菜鸟,也经常在博客上去搜集一些腾讯面试题,但是确还是不敢投腾讯,总感觉自己没有自信,最近也面了一些小公司,也都顺利的拿到了实习offer,但最终实习的目标还是腾讯,希望可以和各位想进腾讯的大佬一起学习,我把在博客上搜集的一些腾讯面经答案整理了一下,希望可以和大家一起学习,写这篇博客的目的一是为了自己可以再对C++进行一个复习,而是希望我整理的答案有错误的或者有不足的地方大家可以给我提出来,我们一起共同学习进步,争取都可以进入自己想进的公司。
腾讯2020年面经
1、多态怎么实现的?
多态分为静态绑定和动态绑定,静态绑定是在编译时就绑定好,是用重载和模板来实现的,动态绑定是用虚函数来实现的,首先根据指针或者引用的对象去找到虚表指针,通过虚表指针找到虚表,再从虚表中找到执行函数的实际地址,执行对应地址的函数指令完成多态行为。
2、构造函数可以是虚函数吗?为什么?
构造函数不可以是虚函数。原因:对象是通过构造函数来进行实例化的,如果构造函数定义为虚函数,那么构造函数就会存放在虚表中,虚表是需要虚表指针来找到的,而虚表指针存放在对象中,这样其实是很矛盾的,是一个死循环,所以构造函数不能被定义为虚函数。
3、析构函数可以是虚函数吗?为什么?
析构函数可以是虚函数,并且一般建议写成虚函数。原因:如果是一个基类指向的对象是派生类,那么这个析构函数就得定义成虚函数,此时delete时就会先进到派生类的析构函数中,在派生类的析构函数中会先去调用基类的虚构函数,然后再去调用派生类的析构函数,这样派生类的对象就会被完全释放掉,如果不给析构函数定义成虚函数,那么就只会调用基类析构,则派生类对象的析构函数就不完整。
4、const是函数签名吗?有什么作用?
const是签名函数。作用:区分是只读操作还是赋值操作。
5、C++11了解过吗?
列表初始化、类型推导auto、范围for循环、右值引用、lambda表达式、线程库、异常、智能指针、特殊类设计、空间适配器
6、template讲一下?
template是模板编程,编写与具体类型无关的通用代码,减少程序员重复的工作量,模板编程分为类模板和函数模板,极大地提升了代码的可重用性,使用类模板之后在生成实例化对象时一般要显式实例化。
7、右值引用?
作用是:为了提高代码效率。右值引用最大的作用是移动构造和移动赋值,因为对于拷贝构造,左值引用是一个深拷贝,右值引用是一个浅拷贝,也叫移动构造,直接获取将亡值(右值)的资源,右值引用表示指向的实体为右值,实体的资源是可以被直接拿走,提高拷贝的效率,本质为浅拷贝,赋值拷贝是一样的对于右值引用来说本质都是一个浅拷贝,所以会大大提高代码的效率。
8、lambda表达式?
Lambda表达式结构式{},[]里面是捕捉列表,可以传值或者传引用,()里面是参数列表。
9、智能指针干嘛的,大概怎样实现的?
智能指针是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露。
智能指针有auto_ptr、unique_ptr、shared_ptr、weak_ptr
auto_ptr:当发生拷贝构造时会出现管理权转移的问题,有解引用异常的风险,当发生管理权转移后,智能指针不再拥有该资源,并且也无法访问该资源。
unique_ptr:在auto_ptr的基础上把拷贝构造和赋值置为删除状态,防拷贝
shared_ptr:加了引用计数,当想要释放这个资源时,可以先对引用计数进行减减,如果引用计数为0时说明此时可以释放该资源,当引用计数大于0时说明此时该资源被多个智能指针管理着,此时只能对引用计数进行减减,并不去释放该资源。
weak_ptr:解决特殊场景下的循环引用问题
10、override和final的作用?
override:强制子类去重写父类虚函数
final:定义一个不能被继承的类的时可以用final
11、delete删除数组时为什么会造成内存泄露?
因为只调用了一次析构函数。
12、static和const各种场景的用法?
static:一般对于c++中类用static可以去修饰静态成员变量和静态成员函数,静态成员函数和静态成员变量都只能在类外进行初始化,并且静态成员函数中没有this指针,因为静态成员函数是先于对象存在的,所以还可以用类名+作用域去访问静态成员函数和静态成员变量。static在设计单例模式中还有很大的作用。
const:const一般是用来表示一个变量为常量的,不可进行直接修改。
13、new和malloc的区别?
new和malloc都只在堆上去开辟空间,但是malloc开辟空间时需要去手动指定开辟空间的一个具体大小,malloc不会进行初始化,而new会进行初始化,new进行开辟空间时会调用构造函数,new是关键字,而malloc是函数,所以new的效率是高于malloc的,当内存分配失败后,malloc会返回NULL,而new会抛异常。
14、STL中vector/List的实现
STL:仿函数、空间适配器、算法、容器、迭代器、配接器
vector是底层是用顺序表去实现的,成员变量是由三个指针构成的,第一个指针指向顺序表头部,第二个指针指向有效元素最后一个位置,第三个指针指向开辟空间最后一个位置,当空间不够时需要重新去开辟一个空间,把原先数组里面的内容拷贝到新开辟空间,迭代器可用原生指针去实现。
List底层实现是用带头双向循环链表去实现的,最重要的是迭代器的实现,因为list是一个链表,空间不一定是连续的,如果直接使用原生指针是不对的,需要对迭代器进行封装,采用运算符重载,迭代器加加操作就是让节点指向它的下一个节点,其他的依次用运算符重载去进行封装。
15、map/unordered_map的实现,哈希表相关问题(哈希冲突)
map:底层实现是红黑树,效率是O(logN)
Unordered_map底层实现是哈希表,效率是O(1)
哈希冲突:不同的数据映射到同一个位置
哈希函数:常用的是除留余数法
解决哈希冲突:闭散列和开散列
闭散列:线性探测、二次探测
开散列:拉链发、哈希桶(数组下面挂一个链表)
16、红黑树和AVL树的特性和区别
红黑树:根必须为黑色,红色节点只能接黑色,而黑色节点可以接任意颜色,每条路径黑色个数必须相同,最大路径是最短路径的两倍
AVL树:依靠平衡因子来维持的
红黑树的效率要比AVL树的效率高,因为红黑树是一个近似平衡的二叉搜索树,而AVL树是一个高度平衡的二叉树,对于map和set来说需要进行插入的次数较多,而AVL树由于高度平衡,所以需要旋转的次数比红黑树旋转次数多,所以map和set底层实现要用红红黑树。
17、纯虚函数?
纯虚函数是在虚函数的基础上给虚函数赋值为0,纯虚函数没有函数体,也不能够被调用,包含纯虚函数的类叫做抽象类,抽象类不能够进行对象的实例化,纯虚函数只是为了实现一个接口,起到规范作用,规定继承这个类的程序员必须实现这个函数。
18、堆和栈?
栈由操作系统自动申请和释放空间,在堆上开辟的空间必须由程序员手动去释放,不然会造成内存泄露,栈拥有的空间大小远远小于堆拥有的空间大小,栈是向下生长,堆是向上生长。
19、select和epoll
select:select、poll、epoll是Io多路转接的三种方式,Io多路转接可以完成大量文件描述符的监控,对于select和epoll来说各自有各自的优缺点,select跨平台移植性强,超时时间可以精确到微秒,但是缺点也很明显,select采用的是轮询遍历,遍历效率不如epoll,随着监控描述符的增多,监控效率也会大大下降,select可以监控的文件描述符个数是有限的,是1024个,这个是由操作系统决定的,select监控文件描述符时需要先拷贝到内核空间,当检测到有文件描述符就绪后,就会继续拷贝到用户空间去,select在返回的时候,会将未就绪的文件描述符从事件集合中清除掉该文件描述符,当下次继续监控该文件描述符时又会重新添加,select并不会直接告诉程序员哪些文件描述符就绪了,需要在返回的时候程序员自己去判断。
epoll:目前来说epoll是linux当中公认的监控效率最高的,它底层采用的红黑树进行遍历,所以监控效率相对于select和poll来说是高了很多,select和poll都是水平触发方式,而EPOLLLT是epoll的默认工作方式,边缘触发EPOLLET也只是epoll才拥有。
20、IPC就是进程间通IPC?
信,对于进程间通信常用的有五种方式
管道:匿名管道和命名管道,匿名管道只适用于亲属之间通信,例如父子进程,因为管道是操作系统在内核中开辟了一段缓冲区,匿名管道对于这段缓冲区没有标识符,pipe函数,命名管道可以用于任意两个进程之间进行通信,mkfifo
共享内存:先在物理内存中开辟一段空间,然后各个进程通过页表结构把物理内存映射到自己的虚拟地址空间的共享区,各个进程之间通过修改虚拟地址空间的共享区的地址来进行通信的
消息队列:在内核中创建一队列,队列中每个元素是一个数据报,不同的进程可以通过句柄去访问这个队列。消息队列提供了⼀个从⼀个进程向另外⼀个进程发送⼀块数据的⽅法。
信号量
Socket编程
21、三次握手、四次挥手?
三次握手:客户端先给服务端发送SYN建立连接的请求,服务端收到客户端发送的请求后给回复一个ACK确认,并且同时给回复一个SYN建立连接的请求,此时已经完成了两次握手,客户端收到了服务端的确认和建立连接的请求,他也还会给服务端回复ACK确认,此时三次握手完毕
为什么不进行两次握手就可以了?
第二次握手是服务端给客户端的一个确认,并且同时给客户端发送了SYN建立连接请求,客户端进行第三次握手是为了给服务端回复一个确认。
为什么不进行四次握手?
第三次握手客户端已经给服务端回复了确认,如果再来第四次握手,就会一直陷入一个循环。
四次挥手:客户端先给服务端发送FIN断开连接请求,服务端收到后给客户端回复ACK确认,然后服务端也给客户端发送FIN断开连接的请求,客户端收到后给服务端回复一个ACK确认,此时客户端并没有真正的断开,而是处于一个time_wait的状态,需要等待2MSL时间才会真正的退出,在这段时间内,端口还是被占用着的,也还是可以去接受数据的。
22、MySql存储引擎?
一般常用的是innodb和MYISAM,一般使用的innodb,因为innodb支持事务,还能保证线程安全
23、索引
主键索引、唯一键索引、普通索引、全文索引
主键索引和唯一键索引都是只要创建了主键或者唯一键以后自动生成主键索引和唯一键索引,普通索引是给index,全文索引前提是存储引擎是MYISAM,但是MYISAM不支持事务和线程安全,所以一般不考虑全文索引。
24、事物的ACID特性和隔离级别
ACID:隔离性、一致性、原子性、持久性
隔离级别
未提交读:脏读、幻读、不可重复读
已提交读:不可重复读、幻读
可重复读
可串行化
25、GDB调试
l:查看代码
b:行号 在这一行开始下断点
i b:查看断点信息
r:让程序跑起来
n:逐过程执行
s:逐语句执行
bt:查看调用堆栈
f:进入到具体
26、一个C++空类编程默认实现的六个函数
构造函数、拷贝构造、析构函数、赋值操作符重载函数、取地址操作符重载函数、const修饰的取地址符重载函数
27、多线程和多进程的优缺点?
28、linux常用命令?find和grep还有awk的使用?
Linux的常用命令:ls、pwd、cd、ll、chmod、touch、mkdir、cp、mv
find [路径] -name [待查找文件名称]
greap “字符串” [path] -r
AWK是一种处理文本文件的语言,是一个强大的文本分析工具
29、进程同步和线程同步?
30、游览器输入URL的整个过程?
DNS进行域名解析出ip
根据ip建立TCP连接(三次握手)
建立连接后发起http请求
服务器响应http请求
浏览器解析HTML代码并请求html中的静态资源(js,css)
关闭TCP连接(四次挥手)
游览器渲染页面
31、TCP四次挥手状态?
32、文件系统?
存储文件时:一般是把文件分成不同的block块,从block bitmap中去查找到空闲的data block块,将文件存储在空闲的块中,然后对文件进行描述,从innod bitmap中查找到空闲的innod节点,在从innod table中去拿取空闲的节点,然后用文件名称+innod节点号去存储该文件。
获取文件:在目录中根据文件名称和innod节点号去找到innod节点,根据innod信息,查找到data blocks中对应的块,将这些块组织在一起就获取到了完整的文件信息。
33、C++内存模型?
分区的原因:通过对不同数据进行分类,可以方便访问、节约空间和方便管理。对于临时数据和多次使用的代码因为生命周期短,因此放入栈区。全局和静态变量可能在整个程序中都需要访问,因此需要单独管理。堆区可由用户自行分配方便管理
栈区:向下生长,由操作系统自动分配和释放
堆区:向上生长,由程序员手动分配和释放空间
静态区:存储静态局部变量、静态全局变量、全局变量等,虚函数也是放在静态区的
常量区:存储常量,不可被修改
代码区:存放程序编译后的指令
34、TCP和UDP的区别?
TCP:建立连接、可靠传输、面向字节流
UDP:不建立连接、不可靠传输、面向数据报,没有拥塞控制
TCP会产生TCP粘包问题、UDP会产生分片问题
以上面试题只是一小部分,我会继续去整理的,如果答案有错误的或者不足的大家可以提出来,我想在不断地交流和探讨中,一定会有一个不错的收获,最后祝愿大家可以早日进入自己理想的公司。