一、面向对象的本质
面向对象 = 数据 + 操作数据的方法 捆绑在一起
目的:高内聚、低耦合、易复用、易维护。
三大特性(深度版):
- 封装:把数据藏起来,只暴露接口(安全、可控)
- 继承:复用代码,扩展功能(代码复用)
- 多态:父类指针指向子类对象,调用不同实现(灵活扩展)
二、封装深度理解
1. 封装不是私有变量那么简单
它的真正意义:
- 隐藏实现:外面不知道内部怎么存、怎么算
- 控制访问:只能通过我允许的方式修改数据
- 降低耦合:我内部改代码,外面不用动
cpp
class User {
private:
int age; // 私有数据,外部不能直接碰
public:
void setAge(int a) { // 我控制怎么赋值
if (a < 0 || a > 150) return;
age = a;
}
};
2. 类的内存本质
对象内存 = 成员变量总和
成员函数不占对象内存! 所有对象共享一套代码。
cpp
class A {
int a;
void f() {}
};
// sizeof(A) = 4(只存 int)
三、继承深度理解(重点+坑点)
1. 继承本质
子类对象 = 父类部分 + 子类新增部分
父类在前,子类在后。
cpp
class Base { int a; };
class Derive : public Base { int b; };
// 内存布局:[ a | b ]
2. 三种继承权限(必须懂)
public:父类public/protected保持不变protected:父类public变protectedprivate:父类所有都变private
3. 构造/析构调用顺序(必考)
构造:父类 → 成员对象 → 子类
析构:子类 → 成员对象 → 父类
4. 父类析构函数必须是 virtual!
cpp
~Base() = default; // ❌ 内存泄漏
virtual ~Base() = default; // ✅ 正确
原因:
父类指针删除子类对象时,只有虚析构才能调用到子类析构。
5. 菱形继承 + 虚继承(难点)
Student Teacher
\ /
People
问题:子类有两份 People
解决:虚继承
cpp
class Student : virtual public People {}
本质:加一个指针,共享父类数据,消除冗余。
四、多态深度理解(最核心、面试必问)
1. 多态的本质
同一个接口,不同实现
cpp
Base* p = new Son();
p->show(); // 调用 Son 的 show ✅ 多态
2. 多态的底层原理(超级重点)
虚函数 + 虚表 + 虚指针
- 有虚函数的类,编译器生成虚表(vtable)
- 对象里多一个虚指针(vptr)
- 调用时通过虚指针 → 虚表 → 找到函数地址
内存布局(有虚函数)
对象:
[vptr][成员变量...]
虚表:
函数1地址
函数2地址
...
多态调用过程
p->func()
→ 取对象前4/8字节 vptr
→ 找到虚表
→ 查表得到函数地址
→ 调用
3. 多态成立的三个条件
- 有虚函数
- 子类重写(override)虚函数
- 父类指针/引用指向子类对象
4. 纯虚函数 & 抽象类
cpp
virtual void func() = 0;
- 没有实现
- 类变成抽象类
- 不能创建对象
- 强制子类必须实现
五、四大函数深度理解(OOP灵魂)
任何一个类,自动生成4个函数:
- 构造函数
- 析构函数
- 拷贝构造
- 拷贝赋值
1. 浅拷贝 vs 深拷贝(超级坑)
- 浅拷贝:只拷贝指针(两个对象共用一块内存)
- 深拷贝:重新开辟空间,拷贝数据(安全)
有指针必须写深拷贝!
cpp
A(const A& other) {
data = new int(*other.data); // 深拷贝 ✅
}
2. 移动语义(C++11 现代OOP)
cpp
A(A&& other) { // 移动构造
data = other.data;
other.data = nullptr;
}
偷别人的资源,不拷贝,超快!
六、重载 / 重写 / 隐藏(彻底分清)
1. 重载(overload)
同一个类,同名函数,参数不同
cpp
void f(int);
void f(double);
2. 重写(override)
子类重写父类虚函数
- 函数名/参数/返回值完全一样
- 必须有 virtual
3. 隐藏(hide)
子类函数与父类同名,没有 virtual
- 子类隐藏父类函数
- 不属于多态
七、面向对象设计原则(企业级)
- 单一职责:一个类只干一件事
- 开闭原则:对扩展开放,对修改关闭
- 里氏替换:子类可以替换父类
- 接口隔离:接口小而专
- 依赖倒置:依赖抽象,不依赖具体
八、面试必问 12 题(答案直接背)
- 多态底层原理?
虚指针 + 虚表 - 父类析构为什么要 virtual?
防止内存泄漏,保证子类析构被调用 - 浅拷贝和深拷贝区别?
浅拷贝共用内存,深拷贝独立内存 - 什么是抽象类?
有纯虚函数,不能实例化 - 类的大小由什么决定?
成员变量,不含成员函数 - 菱形继承问题?
数据冗余,虚继承解决 - 构造析构顺序?
父类→成员→子类;逆序析构 - 重载、重写、隐藏区别?
参数不同/虚函数重写/同名无虚函数 - 空类大小?
1字节 - 成员函数存在哪里?
代码段,所有对象共享 - this指针是什么?
指向当前对象的指针 - 什么时候用多态?
统一接口,不同行为
九、终极总结(背会这一段)
- 封装:数据私有,接口公开,安全可控
- 继承:复用代码,扩展功能,顺序构造
- 多态:虚表+虚指针,父类指针调用子类实现
- 深拷贝:有指针必须写
- 虚析构:继承必须加
- 面向对象 = 数据 + 行为 + 可扩展