美团移动端 C++开发 一面 面经
1. 虚函数表的实现原理是什么?虚函数表和普通成员函数分别存储在哪里?
参考答案:
编译器为每个包含虚函数的类生成一个虚函数表(vtable),表中存储该类所有虚函数的地址。每个对象内部有一个隐藏的vptr指针,指向该类的虚函数表。当通过基类指针调用虚函数时,程序通过vptr找到虚函数表,再根据函数索引找到对应函数地址并调用,这个过程是运行时决定的,实现了多态。
- 虚函数表存储在程序的只读数据段(.rodata)或代码段,编译期就确定了,一个类只有一个虚函数表,所有该类对象共享
- 对象中的vptr存储在对象的内存空间中,通常在对象内存布局的最开始位置,如果对象在栈上vptr就在栈上,在堆上就在堆上
- 普通成员函数的代码存储在代码段(.text段),调用时直接通过函数地址调用,编译期就确定了,不需要运行时查表,所有对象共享,不占用对象内存
2. 菱形继承会导致什么问题?C++如何通过虚继承解决?
参考答案:
菱形继承是指一个类通过多条路径继承同一个基类,比如类D同时继承B和C,而B和C都继承自A。这会导致D中有两份A的成员变量造成数据冗余,访问A的成员时产生二义性,以及A的构造函数被调用两次。
- 使用virtual关键字让B和C虚继承A,这样D中只会保留一份A的成员
- 编译器为虚基类生成虚基类表指针(vbptr),表中存储虚基类成员相对于当前对象的偏移量,通过间接寻址访问虚基类成员
- 构造顺序变化:最底层派生类D负责初始化虚基类A,然后按继承顺序构造中间类B和C,最后构造D自己
- 虚继承会带来额外开销:需要虚基类表指针,访问虚基类成员需要间接寻址性能略降,对象大小增加,因此只在确实需要解决菱形继承时才使用
3. const int *p和int * const p有什么区别?
参考答案:
这两种声明的区别在于const修饰的对象不同。
const int *p是指向常量的指针,const修饰的是*p即指针指向的内容,不能通过p修改指向的值但可以改变指针的指向,也可以写成int const *pint * const p是常量指针,const修饰的是p本身,可以通过p修改指向的值但不能改变指针的指向,指针本身是常量必须在声明时初始化- 记忆技巧:const在
*左边修饰指向的内容内容不可变,const在*右边修饰指针本身指针不可变 const int * const p是既不能改变指针指向也不能改变指向的内容,两者都是常量
4. vector和list的底层数据结构有什么不同?分别适用于什么场景?
参考答案:
vector是动态数组底层是连续内存,list是双向链表每个节点包含数据和前后指针。
- vector支持随机访问O(1),尾部插入删除O(1)但中间插入删除需要移动元素O(n),扩容时需要重新分配内存拷贝所有元素可能导致迭代器失效,内存连续缓存友好遍历效率高
- list不支持随机访问需要遍历O(n),任意位置插入删除O(1)只需修改指针,不需要连续内存不存在扩容问题,每个节点需要两个指针空间内存开销大,缓存不友好遍历效率低
- vector适用于需要频繁随机访问、主要在尾部插入删除、元素数量相对稳定、对内存局部性要求高的场景
- list适用于需要频繁在中间位置插入删除、不需要随机访问、元素数量变化频繁、对迭代器稳定性要求高的场景
- 对于大多数场景vector性能更好,因为现代CPU的缓存机制对连续内存访问非常友好
5. TCP是如何保证可靠传输的?
参考答案:
TCP通过多种机制保证可靠传输。
- 序列号和确认应答:每个TCP报文段都有序列号标识数据字节位置,接收方收到数据后发送ACK确认,发送方通过ACK确认数据是否成功送达
- 超时重传:发送方维护重传定时器RTO,超时未收到ACK就重传数据,采用自适应算法根据RTT动态调整RTO
- 快速重传:接收方收到乱序数据时立即发送重复ACK,发送方收到3个重复ACK立即重传丢失的报文段,不必等待超时
- 滑动窗口:允许发送方连续发送多个数据包不必等待每个包的ACK,窗口大小动态调整提高传输效率
- 流量控制:接收方在ACK中通告自己的接收窗口大小,发送方根据接收窗口调整发送速率,防止接收方缓冲区溢出
- 拥塞控制:通过慢启动、拥塞避免、快重传、快恢复等算法根据网络状况动态调整发送速率
- 校验和:TCP头部包含校验和字段覆盖头部和数据,接收方验证校验和发现错误则丢弃该报文段
- 顺序控制:接收方根据序列号对数据排序,保证数据按发送顺序交付给应用层
6. HTTPS的握手过程是怎样的?为什么需要三个随机数?
参考答案:
HTTPS在TCP连接建立后需要进行TLS/SSL握手来建立安全连接。
- Client Hello:客户端发送支持的TLS版本、加密套件列表、客户端随机数(Client Random)
- Server Hello:服务器选择TLS版本和加密套件,发送服务器随机数(Server Random)和服务器数字证书(包含公钥)
- 客户端验证证书:验证证书的合法性包括CA签名、有效期、域名匹配,检查证书是否被吊销,从证书中提取服务器公钥
- 生成会话密钥:客户端生成预主密钥(Pre-Master Secret)这是第三个随机数,用服务器公钥加密后发送给服务器,服务器用私钥解密得到预主密钥
- 计算会话密钥:客户端和服务器分别用三个随机数通过相同算法生成相同的会话密钥用于后续对称加密
- 切换加密通信:双方发送Change Cipher Spec和Finished消息,验证握手过程的完整性
- 应用数据传输:使用对称加密算法和会话密钥进行加密通信
需要三个随机数的原因:
- 增加密钥的随机性,单个随机数可能不够随机,三个随机数组合大大增加了随机性
- 防止重放攻击,每次连接的随机数都不同,攻击者无法重放之前的握手数据
- 分散风险,即使某个随机数被破解,攻击者仍然难以推导出最终的会话密钥
- 双方共同参与密钥生成,任何一方都无法单独决定会话密钥
7. 什么是中间人攻击?HTTPS如何防御?
参考答案:
中间人攻击(MITM)是指攻击者在客户端和服务器之间插入自己,拦截、篡改或伪造通信内容。攻击者同时与客户端和服务器建立连接,客户端以为在和服务器通信,服务器以为在和客户端通信,实际都在和攻击者通信。
- 常见攻击方式:ARP欺骗劫持局域网流量,DNS劫持将域名解析到攻击者服务器,伪造证书冒充服务器身份,公共WiFi监听截获明文数据
- 数字证书验证:服务器证书由权威CA签发,客户端验证证书的合法性,攻击者无法伪造合法证书
- 非对称加密:使用服务器公钥加密预主密钥,只有持有私钥的服务器能解密,攻击者无法获取会话密钥
- 消息认证码:每个消息都有MAC确保消息完整性防止篡改
- 证书链验证:验证证书的颁发机构,检查证书是否被吊销,验证证书的有效期和域名
- 进一步防御措施:使用HSTS强制HTTPS,证书固定(Certificate Pinning),不信任自签名证书,及时更新根证书列表
8. DNS解析只有浏览器才支持吗?详细说说DNS解析过程
参考答案:
DNS不只是浏览器支持,它是操作系统级别的服务,任何需要网络通信的应用程序都可以使用,包括命令行工具、邮件客户端、即时通讯软件、游戏客户端、移动应用、后端服务器程序等。应用程序通过系统调用请求DNS解析,操作系统负责具体的解析过程。
DNS解析的详细过程:
- 浏览器缓存查询:浏览器维护自己的DNS缓存,如果最近访问过该域名直接返回缓存的IP
- 操作系统缓存查询:查询系统的DNS缓存,检查hosts文件是否有配置
- 本地DNS服务器查询:向配置的本地DNS服务器(通常是ISP提供)发起查询,本地DNS服务器有缓存则直接返回
- 递归查询过程:如果本地DNS服务器没有缓存,会查询根域名服务器获取顶级域名服务器地址,查询顶级域名服务器获取权威域
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

查看24道真题和解析