第3章 C++语言核心考点:内存管理、智能指针、多态、模板
内存管理、智能指针、多态与模板是C++面试中最高频的四组核心能力。面试官通过它们考察你对资源生命周期、运行时多态、零开销抽象及泛型编程的理解深度。本章梳理关键概念与回答框架,助你快速构建体系化知识脉络。
| 考点 | 核心机制 | 典型应用 | 常见陷阱 |
|---|---|---|---|
| 内存管理 | new/delete 与 RAII | 智能指针、资源池 | 内存泄漏、悬空指针 |
| 智能指针 | 引用计数、所有权 | 资源自动管理 | 循环引用、性能开销 |
| 多态 | 虚函数、虚表 | 接口设计、策略模式 | 对象切割、vptr额外内存 |
| 模板 | 泛型、元编程 | STL、enable_if | 代码膨胀、SFINAE可读性 |
面试问答卡片
问题1:谈谈C++11的智能指针及其内存管理优势
面试官考察点: RAII理解、shared_ptr/unique_ptr/weak_ptr辨析、引用计数、循环引用处理
回答框架:
- 智能指针是RAII思想的封装,自动释放资源
- unique_ptr独占所有权,零开销;shared_ptr共享所有权,引用计数;weak_ptr观测不增加计数
- weak_ptr解决shared_ptr循环引用导致的内存泄漏
- 性能:unique_ptr无额外开销;shared_ptr引用计数有原子操作
简短示例回答: C++11提供三种智能指针:unique_ptr独占资源,适合所有权明确场景;shared_ptr通过引用计数实现共享,需注意循环引用;weak_ptr可观测但不拥有,打破循环。它们都确保自动释放,避免手动delete。
可能追问: 引用计数线程安全如何实现?自定义删除器如何使用?如何与C语言回调函数交互?
避坑提醒: 不要把裸指针和智能指针混用;shared_ptr循环引用一定用weak_ptr;unique_ptr可通过move转移所有权。
避坑提醒: 不要把裸指针和智能指针混用;shared_ptr循环引用一定用weak_ptr;unique_ptr可通过move转移所有权。
问题2:C++多态的实现机制是什么?虚函数表如何工作?
面试官考察点: 虚函数、虚表、动态绑定、对象内存布局、性能开销
回答框架:
- 多态通过虚函数实现,基类声明virtual,派生类重写
- 每个含虚函数的类有一个虚表(vtable),存储函数指针
- 对象头部增加vptr指针(8字节),指向所属类的虚表
- 调用时通过vptr间接跳转,实现动态绑定
- 构造函数不能为虚,析构函数通常设为虚
简短示例回答: 基类声明虚函数,派生类重写。每个对象拥有vptr指向类的虚表。调用时根据实际类型从虚表获取函数地址,实现运行时多态。代价是对象增加指针大小,每次调用多一次间接跳转。
可能追问: 虚表在编译时还是运行时生成?多重继承下虚表如何布局?纯虚函数如何实现接口?
避坑提醒: 构造函数中不要调用虚函数;析构函数应为虚;静态成员函数不能为虚。
避坑提醒: 构造函数中不要调用虚函数;析构函数应为虚;静态成员函数不能为虚。
问题3:解释模板特化与SFINAE
面试官考察点: 全特化/偏特化概念、函数模板与类模板差异、SFINAE原理、enable_if用法
回答框架:
- 模板特化:全特化指定所有类型参数;偏特化部分指定(仅类模板支持)
- 函数模板只有全特化,没有偏特化(可通过重载模拟)
- SFINAE:替换失败不是错误,编译器忽略无效重载
- 常用std::enable_if对模板函数进行条件编译
简短示例回答: 全特化如 template<> class MyClass<int> {...}。偏特化如 template<class T> class MyClass<T*> {...}。SFINAE指当模板参数替换产生非法类型时,编译器不报错而移除该重载。例如 std::enable_if<std::is_integral_v<T>> 实现整数类型专用函数。
可能追问: 偏特化为什么不能用于函数模板?SFINAE与concepts的对比?可变参数模板如何与SFINAE组合?
避坑提醒: 函数模板偏特化用重载代替;偏特化匹配优先级易混淆;复杂SFINAE改用concepts提升可读性。
避坑提醒: 函数模板偏特化用重载代替;偏特化匹配优先级易混淆;复杂SFINAE改用concepts提升可读性。