字节 客户端开发-C++ 一面
1.extern "C" 的用途是什么?
主要用于实现 C++ 与 C 语言的混合编程。C++ 支持函数重载,在编译时会将函数名进行重整(Name Mangling)以包含参数类型信息;而 C 语言不支持重载,编译后的符号只是原函数名。用 extern "C" 修饰的代码块,会指示 C++ 编译器按照 C 语言的规则来链接这些函数,从而解决在 C++ 代码中调用 C 语言库,或暴露 C 接口给其他语言调用的问题。
2. C++ 空类大小是多少?如果只有一个 char 成员的类,大小是多少?
- 空类大小为 1 个字节。 C++ 标准规定每个实例化对象必须在内存中拥有独一无二的地址,因此编译器会隐式地为空类插入 1 个字节的占位符。
- 只有一个 char 成员的类大小也是 1 个字节。 因为此时类已经有了实际的成员变量,不需要额外的占位符,且不需要复杂的内存对齐。如果有虚函数,则由于需要存放虚函数表指针(vptr),大小会变成 8 字节(64位系统下)。
3. 面向对象的封装、继承、多态由于哪个最重要?C的 struct 和 C++ 的类有什么区别?
- 多态最重要。 封装解决了数据安全与隐藏问题,继承解决了代码复用问题;而多态是面向对象设计的灵魂,它使得接口与实现彻底分离,是设计模式(如策略模式、工厂模式)和开闭原则(对扩展开放,对修改关闭)赖以实现的核心基础。
- 区别: 在 C 语言中,struct 只能定义数据成员,不能定义方法,且不支持权限控制(默认全公开);在 C++ 中,struct 和 class 几乎等价,唯一的区别在于默认的访问控制权限和默认继承机制:struct 默认是 public,而 class 默认是 private。
4. STL常用容器有什么?vector 和 map 的 erase 返回值是什么?
- 常用容器: 顺序容器有 vector、deque、list;关联容器有 map、set(红黑树实现)以及无序关联容器 unordered_map、unordered_set(哈希表实现)。
- erase 的返回值: 在 C++11 之后,vector::erase 和 map::erase 都会返回一个指向被删除元素之后紧邻位置的迭代器。如果在遍历容器时进行删除操作,必须接收这个返回值(如 it = vec.erase(it);),否则会导致迭代器失效甚至程序崩溃。
5. RAII 是什么?为什么需要?
RAII(Resource Acquisition Is Initialization,资源获取即初始化)是 C++ 管理资源、避免泄漏的核心惯用法。它的核心思想是:将资源的生命周期与局部对象的生命周期绑定。在对象的构造函数中申请资源(如分配内存、打开文件、获取锁),在对象的析构函数中释放资源。由于 C++ 保证当局部对象超出作用域(包括异常抛出时)一定会调用其析构函数,因此不需要程序员手动去 delete 或 unlock,极大地提高了异常安全性。
6. 既然提到了 RAII 管理资源,C++11 中智能指针的底层原理是什么?如何解决 shared_ptr 的循环引用问题?
智能指针是 RAII 的典型应用。std::shared_ptr 的底层基于引用计数控制块来实现共享所有权。每拷贝一次,控制块中的强引用计数加 1;当对象析构时计数减 1,为 0 时自动释放堆内存。循环引用问题: 当两个对象通过 shared_ptr 互相持有对方时,它们的强引用计数永远无法降为 0,导致内存泄漏。解决办法: 引入 std::weak_ptr 打破循环。weak_ptr 用于观测 shared_ptr,它不会增加强引用计数,当需要访问对象时通过 lock() 方法提升为临时的 shared_ptr,从而安全地解决互相依赖。
7. TCP 的可靠性体现在哪里?与 UDP 对比有什么区别?
- TCP 可靠性: 通过校验和、序列号与确认应答(ACK)机制保证数据无差错、不丢失、不重复且按序到达;拥有超时重传、滑动窗口机制进行流量控制;拥塞控制(慢启动、拥塞避免等)防止拖垮网络。
- 对比 UDP: TCP 是面向连接的、可靠的字节流服务,有状态,开销大,延迟相对较高;UDP 是无连接的、尽最大努力交付的数据报服务,无拥塞控制,开销极小,速度快,适用于实时性要求高(如音视频通话、FPS游戏)的场景。
8. 在聊天系统底层的网络通信中,如何设计心跳保活机制?为什么通常不建议单靠 TCP 自带的 Keep-Alive?
聊天系统中,客户端和服务器之间需要维持长连接。单靠 TCP 内核级的 Keep-Alive 是不够的:它默认计时器较长(通常是两小时),且只能检测网线物理断开等连接层面的崩溃;如果应用层发生了死锁或拥塞(假死),TCP 依然认为是连通的。设计方案:应用层心跳。 客户端定时(如每 30 秒)向服务端发送轻量级的 Ping 包;如果服务端收到则更新该用户的最后活跃时间,并回复 Pong。如果服务端后台的定时任务发现某个用户超过 3 次未发送心跳,直接在其应用层强制清理连接并标记该用户为离线状态。
9. 聊天系统为什么同时使用 Redis 和 Elasticsearch?能不能用 Redis 替代 ES?
在聊天系统中,两者的职责完全不同,且相互补充:
- Redis 主要作为内存缓存与高吞吐层的基石。用于存储用户在线状态、最后一条消息预览、最近常联系的会话列表,以及通过 Pub/Sub 进行节点间的简单信令分发。
- Elasticsearch 主要解决分词搜索需求。用于历史聊天记录的多关键词模糊检索(例如在群聊中搜
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.
