Appearance
C++ 面向对象(OOP)与多态专题
一句话总览
OOP 三大特性:封装、继承、多态。C++ 面试 OOP 部分几乎都围绕 虚函数、多态实现、类内存布局、构造/析构 展开,且极喜欢面试官追问「为什么这么设计」。
class 本身的经典问题(struct/class 区别、特殊成员函数、copy-and-swap、类模板、陷阱速查)已汇总在
class.md;本页是问题清单式入口,细节按子文档下钻。
问题清单(含答案)
概念 / 特性
1. 面向对象三大特性是什么?
答案
封装(隐藏实现、只暴露接口)、继承(复用 + is-a 关系)、多态(同一接口、不同实现)。
2. C++ 与其它语言 OOP 差异、struct vs class?
答案
struct 默认 public、class 默认 private;C++ 支持多继承、虚继承、RTTI、模板,Java 是单继承 + 接口。
3. 重载 / 重写 / 隐藏 的区别?
答案
重载(overload)同作用域同名不同参、编译期确定;重写(override)派生类覆盖基类虚函数、运行期多态;隐藏(hide)派生类同名函数遮蔽基类(非虚时即使签名不同也算隐藏)。
4. 默认生成的(五个/六个)特殊成员?
答案
默认构造、析构、拷贝构造、拷贝赋值、移动构造、移动赋值(移动只在没自定义拷贝/析构时默认生成)。三/五法则:自定义了拷贝/析构通常也要补全其余。
虚函数 / 多态(重点中的重点)
5. 什么是多态?编译期 vs 运行期?
答案
同一接口多种实现。编译期多态(模板、重载)编译期确定调用;运行期多态(虚函数)运行期通过 vtable 动态绑定。
6. vtable 与 vptr 的内存布局?
答案
含虚函数的类对象头部有一个 vptr,指向该类的 vtable(虚函数地址表)。vtable 每类一份、存于只读数据段;每个对象各持一个 vptr。详见 vtable.md。
7. 为什么析构函数要写成虚函数?为什么构造函数不能?
答案
基类指针 delete 派生类对象时,虚析构保证调到派生类析构,否则只析构基类部分 = 泄漏/UB。构造函数不能虚:构造时对象类型未"定形"(vptr 尚未指向派生类表),且虚构造无意义。
8. 纯虚函数、抽象类、接口类?
答案
virtual ... = 0 纯虚函数使类成为抽象类、不能实例化;全纯虚、无数据 = 接口类(类似 Java interface)。
9. 虚函数表存在哪里?一个类几个 vptr?
答案
vtable 在只读数据段(.rodata)。普通单继承一个 vptr;多继承每个非空基类子对象一个 vptr(可能多个)。
10. 基类指针 delete 派生类对象安全吗?
答案
只有基类析构是虚函数才安全;否则 UB(只释放基类部分、可能泄漏)。
11. 静态绑定 vs 动态绑定?
答案
静态绑定编译期确定地址(普通函数、非虚调用);动态绑定运行期经 vptr → vtable 间接跳转(虚函数),故有轻微开销但支持多态。
类内存 / 对象模型
12. 空类大小?为什么是 1?
答案
1 字节,保证每个对象有唯一地址(&a != &b)。
13. 有虚函数后对象大小加了多少?vptr 放哪?
答案
加一个 vptr 的大小(64 位 8 字节),vptr 放在对象头部。
14. 多继承、菱形继承?
答案
多继承多个基类子对象依次排布、多个 vptr;菱形继承用虚继承,通过虚基类表(vbptr)共享唯一基类子对象,消除二义性。详见 inheritance-deep.md。
15. struct 布局要点?
答案
内存对齐(按最大成员对齐、中间补 padding)、位域(节省空间、按实现打包),见 memory/alignment.md。
子文档
| 文件 | 内容 |
|---|---|
class.md | class 总览:struct/class/union、访问控制、特殊成员函数(0/3/5)、构造析构顺序、copy-and-swap、虚函数、类模板、陷阱速查 |
polymorphism.md | 多态机制、动态绑定 |
vtable.md | 虚表/虚指针内存模型、对象大小 |
virtual-destructor.md | 虚析构/构造辨析、特殊成员函数三/五规则 |
concepts.md | 重载重写隐藏、struct/class/union、访问控制 |
inheritance-deep.md | 多继承/菱形/虚继承布局与二义性、this、thunk |
rtti-typeinfo.md | RTTI:typeid / dynamic_cast / type_info / -fno-rtti |