昆仑天工 - C++软件开发 一面

1. 自我介绍

(开放性问题,候选人应包含教育背景、技术栈、项目经验、个人优势,控制在2分钟以内)

2. vector和list的区别是什么?各自适合什么场景?

参考答案:底层结构不同导致性能特性完全不同:

  • vector底层是连续内存数组,list底层是双向链表
  • 随机访问:vector支持O(1)下标访问,list不支持随机访问只能遍历O(n)
  • 插入删除:vector在中间插入需要移动元素O(n),list在任意位置插入只需修改指针O(1)
  • 内存:vector内存连续缓存友好,list每个节点单独分配内存有额外指针开销
  • 扩容:vector容量不足时会重新分配并拷贝所有元素,list无此问题
  • 适用场景:vector适合频繁随机访问、尾部增删的场景;list适合频繁在中间插入删除、不需要随机访问的场景

3. C++的动态内存管理机制是怎样的?

参考答案:C++提供了两套动态内存管理机制:

  • 底层机制:new/delete和malloc/free。new会调用构造函数,delete会调用析构函数;malloc/free只分配释放内存不涉及对象构造
  • 内存分配来源:堆内存,由操作系统管理,程序员手动申请和释放
  • 常见问题:内存泄漏(申请未释放)、野指针(释放后继续使用)、重复释放(double free)
  • 现代C++解决方案:智能指针自动管理内存生命周期 unique_ptr:独占所有权,不可拷贝,离开作用域自动释放shared_ptr:共享所有权,引用计数为0时自动释放weak_ptr:弱引用,不增加引用计数,解决循环引用问题
  • RAII原则:资源获取即初始化,利用对象析构函数自动释放资源,是C++内存管理的核心思想

4. 什么是虚函数表?多继承下虚函数表是怎么工作的?

参考答案:虚函数表是C++实现运行时多态的底层机制:

  • 每个含有虚函数的类都有一张虚函数表(vtable),存储该类所有虚函数的地址
  • 每个对象实例的内存起始位置有一个虚函数指针(vptr),指向所属类的虚函数表
  • 调用虚函数时,通过vptr找到vtable,再根据函数索引找到实际函数地址并调用,实现运行时多态
  • 派生类会继承基类的vtable,并将被重写的虚函数地址替换为自己的实现

多继承下的虚函数表:

  • 派生类会有多个vptr,每个基类对应一个
  • 对象内存布局中,每个基类子对象都有自己的vptr
  • 调用不同基类的虚函数时,使用对应基类的vptr
  • 菱形继承会导致基类数据重复,需要用虚继承解决,虚继承会引入虚基类表(vbtable)

5. 多继承有哪些弊端?

参考答案:多继承功能强大但问题也多:

  • 菱形继承问题:D继承B和C,B和C都继承A,D中会有两份A的数据,造成数据冗余和二义性访问
  • 命名冲突:多个基类有同名函数时,调用时产生二义性,需要显式指定基类
  • 内存布局复杂:多个vptr增加对象大小,内存布局复杂难以理解
  • 维护困难:继承关系复杂,代码可读性差,修改一个基类可能影响多个派生类
  • 虚继承开销:解决菱形继承需要虚继承,引入额外的vbtable和间接访问开销
  • 实践建议:优先使用组合代替继承,多继承只用于接口类(纯虚函数类),避免多继承实现类

6. C++11的右值引用和移动语义是什么?

参考答案:右值引用和移动语义是C++11最重要的性能优化特性:

  • 左值和右值:左值有明确的内存地址可以取地址,右值是临时对象或字面量没有持久地址
  • 右值引用(&&):专门绑定到右值,延长临时对象的生命周期
  • 移动语义:通过移动构造函数和移动赋值运算符,将资源的所有权从一个对象转移到另一个对象,而不是拷贝
  • 核心价值:避免不必要的深拷贝,将O(n)的拷贝操作变成O(1)的指针转移
  • std::move:将左值强制转换为右值引用,触发移动语义,转移后原对象处于有效但未定义状态
  • 典型场景:函数返回大对象、容器插入元素、unique_ptr转移所有权
  • 完美转发:std::forward配合万能引用,保持参数的左值/右值属性传递给下一个函数

7. 动态多态和静态多态的区别及使用场景?

参考答案:两种多态的实现机制和性能特性完全不同:

  • 动态多态:通过虚函数和继承实现,运行时根据对象实际类型决定调用哪个函数 实现:基类声明virtual函数,派生类override开销:虚函数调用需要通过vptr间接寻址,有运行时开销场景:对象类型在运行时才能确定,如插件系统、工厂模式、游戏中不同类型的角色
  • 静态多态:通过模板和函数重载实现,编译期确定调用哪个函数 实现:函数重载、运算符重载、模板特化、CRTP(奇异递归模板模式)开销:编译期展开,零运行时开销场景:类型在编译期已知,追求极致性能,如STL容器、数学库
  • 选择原则:类型关系在编译期确定用静态多态,运行时才能确定用动态多态;性能敏感场景优先静态多态

8. 如何在二叉树中找到两个节点的最近公共祖先?

参考答案:最近公共祖先(LCA)是经典算法题,有多种解法:

  • 递归解法(最优): 如果当前节点为空或等于p或q,直接返回当前节点递归在左子树和右子树分别查找p和q如果左右子树各找到一个,说明当前节点就是LCA如果只有一侧找到,说明两个节点都在那一侧,返回那一侧的结果时间复杂度O(n),空间复杂度O(h),h为树高
  • 路径比较法:分别找出根节点到p和q的路径,然后找两条路径最后一个公共节点
  • 父节点记录法:用哈希表记录每个节点的父节点,然后

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++八股文全集 文章被收录于专栏

本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

全部评论

相关推荐

爪哇沉淀ing:哎 感觉很丰富 其实没啥含金量 我本科也是理工的 实话实说这个学校真的没啥竞争力 建议还是提升学历
今天你投了哪些公司?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务