一、为什么 C 语言“没有对象”,却处处是对象?
很多人说:
C 是面向过程,C++ / Java 是面向对象。
但你只要看过 Linux 内核、驱动、HAL、FFmpeg、libc,就会发现:
👉到处都是 struct + 函数指针。
比如经典结构:
typedef struct { void (*open)(void* self); void (*close)(void* self); } DeviceOps; typedef struct { DeviceOps* ops; int fd; } Device; void device_open(Device* d) { d->ops->open(d); }这真的只是“面向过程”吗?
其实不是。
👉这是 C 语言手写的“对象模型”。
tips:对象模型”可以简单理解为:像 Java 里定义接口 → 写接口实现类 → 用实现类对象,通过接口去调用方法。
二、这段 C 代码,本质上已经具备 OOP 全套能力
上面这段代码已经同时具备:
✅ 数据(fd)
✅ 行为(open / close)
✅ 接口抽象(DeviceOps)
✅ 回调机制(函数指针)
✅ 多态(ops 指向不同实现)
✅ this/self 机制(void* self)
这在设计层面,已经是一个完整的“对象系统”。
三、逐项拆解:C 是如何“手搓 OOP”的
1️⃣ 接口(函数表)
typedef struct { void (*open)(void* self); void (*close)(void* self); } DeviceOps;这本质就是:
👉接口 / 虚函数表 / 回调集合
2️⃣ 对象(数据 + 接口指针)
typedef struct { DeviceOps* ops; int fd; } Device;等价于:
- 成员变量
- 虚函数表指针
3️⃣ 方法调用(多态)
d->ops->open(d);这里发生了三件事:
- 通过 ops 找接口
- 通过接口找实现
- 把 d 作为 self 传入
👉 这就是虚函数调用。
四、翻译成 Java,会发生什么?
C 版本核心调用
d->ops->open(d);
Java 直译版
d.ops.open(d);
Java 正统面向对象写法
d.open();
因为:
- C 需要你手动维护 self
- Java 编译器 / 虚拟机帮你维护 this
Java 完整对应结构
接口(C 的 DeviceOps)
interface Device { void open(); void close(); }实现类(某个具体设备)
class FileDevice implements Device { int fd; @Override public void open() { } }多态调用
Device d = new FileDevice(); d.open();👉 本质和 C 的:
d->ops->open(d);
完全一致。
五、翻译成 C++,你会看到“虚函数表真身”
class Device { public: virtual void open() = 0; virtual void close() = 0; int fd; };编译器背后做的事情,和你在 C 里写的:
DeviceOps* ops;
几乎一模一样。
👉 C++ 只是帮你自动生成并维护了那张函数表。
六、函数指针模型 = 回调模型 = 对象模型
普通回调:
register_callback(on_event);对象模型:
device->ops->on_event(device);
区别只有一个:
👉 对象模型 =一组有语义的回调 + 绑定的数据结构
这也是为什么系统层大量使用 struct + 函数指针:
- Linux driver
- Binder driver
- HAL module
- FFmpeg / libuv / libc
👉 全部都是“接口 + 实现 + 回调 + 多态”。
七、为什么系统层更爱 C 风格“对象模型”?
因为它:
✅ ABI 稳定
✅ 内存布局可控
✅ 无运行时依赖
✅ 跨语言
✅ 性能可预测
✅ 可用于内核 / 驱动 / 启动阶段
而 C++ / Java:
是在此模型之上,提供自动化和安全封装。
八、一句话本质总结(系统工程师版)
👉 面向对象不是语法,是设计思想。
👉 C 用函数指针实现对象。
👉 C++ 用编译器实现对象。
👉 Java 用虚拟机实现对象。
九、对 NDK / Android 系统方向的意义
你以后会不断看到:
Binder 的 struct + ops
HAL 的 hw_module_t
Linux 的 file_operations
FFmpeg 的 AVCodec
你会发现:
👉它们全都是这一个模型。
当你真正理解“函数指针 + struct = 对象模型”,你就已经具备:
✅ 系统接口设计能力
✅ 框架层阅读能力
✅ 架构抽象能力
十、终极总结
C :手动对象系统
C++ :编译器对象系统
Java :虚拟机对象系统
底层实现不同,抽象思想完全统一。