面经(快手_01)
面经
C++ 基础
static的作用是什么?- 修饰局部变量: 只初始化一次局部变量,生命周期延长到整个程序运行期间,但作用域仍然只在当前函数内。
- 修饰全局变量/函数: 表示该符号只在当前源文件内可见,避免和其他文件同名冲突。
- 修饰类的成员变量: 表示这个成员变量属于整个类,而不是某个对象。所有对象共享同一份静态成员变量。
- 修饰类的成员函数: 表示这个函数属于类本身,调用时不依赖具体对象。
- 修饰类成员函数的作用是什么?什么情况下要用静态成员函数?举一个场景
- 作用: 静态成员函数属于类,而不属于某个对象,因此:
- 可以不创建对象直接调用;
- 不能访问非静态成员变量/非静态成员函数;
- 可以访问静态成员变量/静态成员函数;
- 使用时机: 当一个函数的逻辑不依赖某个具体对象的状态,但又希望它在 “类的命名空间” 下时,就适合定义成静态成员函数。
- 场景: 统计对象个数;
- 作用: 静态成员函数属于类,而不属于某个对象,因此:
const静态成员函数内部能否修改类的非静态变量?为什么?C++里静态成员函数不能声明为const- 因为
const成员函数本质上修饰的是隐藏参数this; - 但静态成员函数没有
this指针;
- 因为
- 静态成员函数内部不能直接修改类的非静态变量
- 非静态成员变量属于对象;
- 静态成员函数没有
this; - 所以它不知道要改哪个对象的成员;
- 如果拿到了对象,就可以修改
- 为什么要进行内存对齐?
- 内存对齐是为了让数据按特定边界存放,比如 4 字节数据放在 4 的倍数地址,8 字节数据放在 8 的倍数地址;
- 主要用来 提高访问效率 以及 硬件平台要求必须对齐;
- 什么是虚函数?它的作用是什么?
- 定义: 在基类中用
virtual修饰的成员函数就是虚函数。 - 作用: 虚函数用于实现运行时多态。当我们通过基类指针或基类引用调用函数时,会根据对象的真实类型决定调用哪个函数。
- 定义: 在基类中用
- 虚函数的底层实现机制是什么?
- 核心: 虚函数表(
vtable)+ 虚函数表指针(vptr)。 - 机制:
- 有虚函数的类,编译器通常会为它生成一张虚函数表;
- 对象中会隐藏一个指针
vptr,指向所属类的虚函数表; - 表中存放虚函数地址;
- 调用虚函数时,通过
vptr->vtable查找函数地址再调用;
- 核心: 虚函数表(
- 动态绑定和静态绑定的区别是什么?
- 静态绑定: 也叫 早绑定,编译期确定 调用哪个函数;
- 动态绑定: 也叫晚绑定,运行期确定 对象的真实类型决定调用哪个函数;
STL 容器与数据结构
std::map是怎么实现的?特性和复杂度是多少?std::map底层一般是红黑树实现;- 红黑树是一种自平衡二叉搜索树,保证树高近似
O(log n); key自动有序;- 查找、插入、删除复杂度都稳定在
O(log n);
std::map和std::unordered_map的区别是什么?std::map- 底层:红黑树;
- 元素有序;
- 查找/插入/删除:
O(log n); - 支持范围查询;
std::unordered_map- 底层:哈希表;
- 元素无序;
- 平均查找/插入/删除:
O(1); - 最坏情况可能退化为
O(n);
- 为什么设计这两个不同的
Map?各自的使用场景是什么?map解决 “有序 + 稳定logN” 的需求;unordered_map解决 “无序 + 平均O(1)” 的需求。
vector访问元素时,[]和.at()有什么区别?operator[]- 不做边界检查
- 访问快
- 越界是未定义行为
.at()- 会做边界检查
- 越界会抛出
std::out_of_range - 更安全,但略慢
- 如何释放
vector占用的多余内存?vector的容量和大小是分开的。删除元素后,容量通常不会立刻缩小。std::vector<int>(v).swap(v);
reserve、resize和clear的区别是什么?- 场景题:如果需要频繁读取,选什么数据结构?如果需要频繁写入,选什么?
- 频繁读取:如果是顺序遍历、随机访问很多,优先选
vector/ 数组; - 频繁写入:
- 尾插很多: 还是
vector,O(1)的时间复杂度,并且可以提前reserve - 中间频繁插入: 可考虑 **链表
list**,已知位置插删O(1);
- 尾插很多: 还是
- 频繁读取:如果是顺序遍历、随机访问很多,优先选
计算机网络与操作系统
- 为什么
HTTPS比HTTP更安全?- 因为
HTTP是明文传输,而HTTPS=HTTP+TLS/SSL。 HTTPS提供了三件关键能力:- 加密性: 防止数据被窃听;
- 完整性: 防止数据在传输过程中被篡改;
- 身份认证: 通过数字证书验证服务器身份,防止伪装网站、中间人攻击。
- 因为
HTTPS的加密机制是什么?- 握手阶段用非对称密码体系解决身份认证和密钥协商
- 数据传输阶段用对称加密保证高效通信。
- 线程之间是怎么通信的?
- 线程属于同一进程,天然共享进程地址空间,所以线程通信最常见就是共享内存。
- 常见线程通信方式
- 共享变量 + 锁
- 条件变量
condition_variable; - 信号量;
- 什么是死锁?产生死锁的条件是什么?
- 定义: 多个线程互相等待对方持有的资源,导致所有线程都无法继续执行,这就是死锁。
- 条件:
- 互斥: 资源一次只能被一个线程占用;
- 请求并保持: 线程已经持有资源,同时又请求新资源;
- 不可剥夺: 资源不能被强行抢走,只能主动释放;
- 循环等待: 存在资源等待环;
- 如何避免或解决死锁问题?
- 固定加锁顺序;
- 一次性申请所有资源;
- 使用
try_lock;
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 GYu的妙妙屋!
