Appearance
面向对象概念速查(重载/重写/隐藏/struct/class 等)
一、重载(overload) vs 重写(override) vs 隐藏(hide)
| 概念 | 判定条件 | 发生在 | 例子 |
|---|---|---|---|
| 重载 overload | 同作用域、同名、参数不同 | 同一类内 / 全局 | f(int)、f(double)、f(int,int) |
| 重写 override | 派生类定义与基类虚函数同名同参 | 继承层级、基类须 virtual | void speak() override |
| 隐藏 hide | 派生类定义与基类同名(不管参数),遮蔽基类版 | 继承层级 | 派生 void f(int) 遮蔽基类所有 f |
要点:
- 重载只看参数签名;返回类型不参与重载决议。
- override 要求签名完全一致(含 const、参数类型),否则就是 hide(此时加
override会编译报错,帮你发现 bug)。 - 名字查找规则:派生类先在自己的作用域找,找不到才向上找基类 —— 所以派生类里定义同名会遮蔽基类所有同名(即便参数不同)。要用基类重载需
using Base::f;。
二、struct vs class
| 维度 | struct | class |
|---|---|---|
| 默认访问控制 | public | private |
| 继承默认 | public 继承 | private 继承 |
| 其它 | 成员函数/继承/模板等能力与 class 完全一样 | 同左 |
- 习惯约定:struct 表示数据聚合(POD/简单数据),class 表示带封装行为的对象。语法能力等价,仅默认访问/继承控制不同。
- C 中 struct 只有数据;C++ 是 C 的超集扩展。
三、union vs struct
| struct | union | |
|---|---|---|
| 内存 | 各成员顺序共存(大小≈成员和+对齐) | 各成员共享起始地址(大小≈最大成员) |
| 同时有效 | 所有成员同时可访问 | 同一时刻只有一个成员有效 |
| 用途 | 组合对象 | 节省内存的互斥存储 / 传输协议 |
- union 大小 = 最大成员大小;union 成员在运行期切换时需自行管理当前「活跃成员」。
- C++ 里 union 成员可以是类对象(需注意构造/析构,常用 variant 替代)。
四、三大特性速记
- 封装:数据 + 方法绑在一起,隐藏细节(访问控制 public/protected/private)。
- 继承:复用与扩展,形成 is-a 关系。
- 多态:同一接口、不同实现(见 polymorphism.md)。
C++ 相比 Java:多继承、运算符重载、模板/泛型(编译期多态)、无 GC(RAII)、值语义与引用语义共存(对象可值传递)。
五、访问控制速查
| 访问级别 | 本类 | 派生类 | 外部 |
|---|---|---|---|
| public | ✅ | ✅ | ✅ |
| protected | ✅ | ✅ | ❌ |
| private | ✅ | ❌ | ❌ |
- protected 成员对「派生类对象访问基类部分的 protected 成员」有一定限制(要继承而来的才可访问,不能通过任意 Base 对象访问其 protected)——较细节,面试可答「规则存在,一般只会问本类/派生/外部三级」。实际 C++ 规则:通过派生类类型的对象只能访问继承来的 protected;通过基类类型访问派生类对象里的 protected 不行。
六、构造函数初始化列表 vs 赋值
cpp
class A {
const int c_; // 必须初始化列表
int& r_; // 引用必须初始化列表
Base b_; // 想调参数构造
public:
A(int c, int& x, int v) : c_(c), r_(x), b_(v) {} // ✅ 在进入函数体前完成
};- const、引用、无默认构造的成员只能用初始化列表。
- 初始化列表按声明的顺序初始化(不是列表顺序),常作面试陷阱:若成员声明顺序与列表顺序不一致,先初始化成员可能仍用未赋值变量。
- 在函数体内赋值是「先默认构造再赋值」,多一次构造,且 const/引用成员不可这样。
七、对象切片(object slicing)
按值传递/返回派生类到基类会切割成基类部分:丢失派生数据、丢失多态(按值没有 vptr 作用)。传参用基类引用/指针避免切片。