面向对象深度理解

一、面向对象的本质

面向对象 = 数据 + 操作数据的方法 捆绑在一起

目的:高内聚、低耦合、易复用、易维护

三大特性(深度版):

  1. 封装:把数据藏起来,只暴露接口(安全、可控)
  2. 继承:复用代码,扩展功能(代码复用)
  3. 多态:父类指针指向子类对象,调用不同实现(灵活扩展)

二、封装深度理解

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变protected
  • private:父类所有都变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. 多态成立的三个条件

  1. 有虚函数
  2. 子类重写(override)虚函数
  3. 父类指针/引用指向子类对象

4. 纯虚函数 & 抽象类

cpp 复制代码
virtual void func() = 0;
  • 没有实现
  • 类变成抽象类
  • 不能创建对象
  • 强制子类必须实现

五、四大函数深度理解(OOP灵魂)

任何一个类,自动生成4个函数:

  1. 构造函数
  2. 析构函数
  3. 拷贝构造
  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

  • 子类隐藏父类函数
  • 不属于多态

七、面向对象设计原则(企业级)

  1. 单一职责:一个类只干一件事
  2. 开闭原则:对扩展开放,对修改关闭
  3. 里氏替换:子类可以替换父类
  4. 接口隔离:接口小而专
  5. 依赖倒置:依赖抽象,不依赖具体

八、面试必问 12 题(答案直接背)

  1. 多态底层原理?
    虚指针 + 虚表
  2. 父类析构为什么要 virtual?
    防止内存泄漏,保证子类析构被调用
  3. 浅拷贝和深拷贝区别?
    浅拷贝共用内存,深拷贝独立内存
  4. 什么是抽象类?
    有纯虚函数,不能实例化
  5. 类的大小由什么决定?
    成员变量,不含成员函数
  6. 菱形继承问题?
    数据冗余,虚继承解决
  7. 构造析构顺序?
    父类→成员→子类;逆序析构
  8. 重载、重写、隐藏区别?
    参数不同/虚函数重写/同名无虚函数
  9. 空类大小?
    1字节
  10. 成员函数存在哪里?
    代码段,所有对象共享
  11. this指针是什么?
    指向当前对象的指针
  12. 什么时候用多态?
    统一接口,不同行为

九、终极总结(背会这一段)

  • 封装:数据私有,接口公开,安全可控
  • 继承:复用代码,扩展功能,顺序构造
  • 多态:虚表+虚指针,父类指针调用子类实现
  • 深拷贝:有指针必须写
  • 虚析构:继承必须加
  • 面向对象 = 数据 + 行为 + 可扩展
相关推荐
To_OC3 小时前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
用户128526116027 小时前
我把祖传Java项目重构后,接口响应从3s砍到了200ms,只改了这几行代码
java
鱼鱼不愚与7 小时前
《原来如此 | 第01期:为什么导航软件能预测红绿灯倒计时?》
算法
Linsk7 小时前
组件 = 模板 + 业务逻辑
java·前端·vue.js
星沉远浦8 小时前
用Gemini高效解决Java代码报错难以定位的问题
java
用户2986985301412 小时前
Word 文档字符级格式化:Java 实现方案详解
java·后端
复杂网络12 小时前
论最小 Agent 计算机的形态
算法
笨鸟飞不快12 小时前
从单个服务到集群:一次完整的性能排查复盘
java·前端
荣码12 小时前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
SamDeepThinking12 小时前
Java微服务练习方式
java·后端·微服务