瀏覽代碼

wiki: 新增C语言OOP完整指南并更新索引

- 新增 wiki/source-c-oop.md(原始资料摘要)
- 新增 raw/.../C语言OOP封装完整系列/c-oop.md(完整指南 + C/C++/Java 对比)
- 更新 wiki/index.md 和 wiki/log.md
- 清理冗余原始文件(.docx/.pptx)
- 修正 FreeRTOS 16-内存管理.md
OpenCode 1 月之前
父節點
當前提交
acb77bb2f8

二進制
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/C语言OOP封装完整系列-1080P 60帧-AVC.mp4.docx


二進制
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/C语言OOP封装完整系列-1080P 60帧-AVC_20260505013137.pptx


+ 1224 - 0
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/c-oop.md

@@ -0,0 +1,1224 @@
+---
+tags: [concept, c, oop, embedded, linux-kernel]
+type: guide
+created: 2026-07-23
+---
+
+# C语言面向对象编程完整指南
+
+**一句话本质**:C++ 的 OOP 是编译器帮你写的 C 代码。本文教你手动写出编译器隐藏的那层代码,并获得完全控制权。
+
+---
+
+## 目录
+
+1. [[#一、开胃菜:5 分钟看到你的第一个 C 类]]
+2. [[#二、封装:创建你自己的 C 类]]
+3. [[#三、继承:复用公共字段]]
+4. [[#四、多态:同一个接口,不同的行为]]
+5. [[#五、向下转型:container_of 原理]]
+6. [[#六、四层架构:工业级项目怎么组织]]
+7. [[#七、Linux 内核中的 C-OOP]]
+8. [[#八、速查卡(打印贴墙用)]]
+
+---
+
+## 一、开胃菜:5 分钟看到你的第一个 C 类
+
+先看三个核心对应关系,然后直接上手:
+
+```c
+// C++ 概念          →  C 实现
+// class Student     →  Student.h + Student.c
+// private int id;   →  struct Student { int id; }; 写在 .c 里
+// public void set() →  Student.h 中声明的函数
+// this->id          →  me->id(me 是显式第一个参数)
+```
+
+### 完整的 Student 类(直接复制改类名就能用)
+
+```c
+// ==================== Student.h ====================
+#ifndef STUDENT_H
+#define STUDENT_H
+
+typedef struct Student Student;      // 不透明类型 → "我有这个类,但你别管里面"
+
+void Student_init(Student *me, int id, int grade);
+void Student_deinit(Student *me);
+void Student_setId(Student *me, int id);
+int  Student_getId(const Student *me);
+void Student_setGrade(Student *me, int grade);
+int  Student_getGrade(const Student *me);
+void Student_print(const Student *me);
+
+#endif
+```
+
+```c
+// ==================== Student.c ====================
+#include "Student.h"
+#include <stdio.h>
+
+/* ===== 私有成员(private) ===== */
+struct Student {
+    int id;       // 外部引用 s->id → 编译错误
+    int grade;    // 外部看不见这个字段
+};
+
+/* ===== 私有方法(private) ===== */
+static int is_valid_grade(int g) {
+    return (g >= 0 && g <= 100);
+}
+
+/* ===== 私有静态变量(private static) ===== */
+static int total_students = 0;
+
+/* ===== 构造/析构 ===== */
+void Student_init(Student *me, int id, int grade) {
+    me->id = id;
+    me->grade = is_valid_grade(grade) ? grade : 0;
+    total_students++;
+}
+void Student_deinit(Student *me) {
+    total_students--;
+}
+
+/* ===== 公开方法(public) ===== */
+void Student_setId(Student *me, int id)  { me->id = id; }
+int  Student_getId(const Student *me)    { return me->id; }
+void Student_setGrade(Student *me, int g) { if (is_valid_grade(g)) me->grade = g; }
+int  Student_getGrade(const Student *me)  { return me->grade; }
+void Student_print(const Student *me) {
+    printf("Student{id=%d, grade=%d}\n", me->id, me->grade);
+}
+```
+
+```c
+// ==================== main.c ====================
+#include "Student.h"
+
+int main(void) {
+    Student s;                    // 分配内存(但尚未初始化)
+    Student_init(&s, 1001, 85);   // 构造
+    Student_setGrade(&s, 90);     // 调用方法
+    Student_print(&s);            // → Student{id=1001, grade=90}
+    // s.id = 999;                ← 编译错误!private!
+    Student_deinit(&s);           // 析构
+    return 0;
+}
+```
+
+**创建自己的类只需三步**:
+1. 复制这 3 段代码,新建 `你的类名.h`、`你的类名.c`
+2. 全局替换 `Student` → 你的类名
+3. 在 `struct Student` 里加你的字段,在函数里写逻辑
+
+> 对应 C++:`class Student { private: int id, grade; public: ... };`
+
+---
+
+## 二、封装:创建你自己的 C 类
+
+### 2.1 你遇到的问题
+
+```c
+// 坏代码:全局变量到处可改
+int led_pin = 15;            // 谁都能改 led_pin = 999
+void led_on() { /* ... */ }
+
+// 另一个文件不小心:
+led_pin = 999;                // bug!找了一下午
+```
+
+**封装要解决的就是这个问题**:把数据和操作绑在一起,对外隐藏内部细节。
+
+### 2.2 C 的封装三板斧
+
+| 手法 | C 语法 | 效果 |
+|------|--------|------|
+| 结构体打包 | `struct` | 把相关字段捆在一起 |
+| 信息隐藏 | `.h` 只放声明,`struct` 定义放 `.c` | 外部无法访问成员 |
+| 私有化 | `static` 修饰函数/变量 | 仅本 `.c` 文件可见 |
+| 命名空间 | 模块前缀 `xxx_` | 不同模块函数不会撞名 |
+| 生命周期 | `init()` / `deinit()` 配对 | 规范化构造/析构 |
+
+### 2.3 完整模板:XXX 类骨架
+
+这是你**每次创建新类都要用的模板**。直接复制,替换 `XXX`。
+
+```c
+// ==================== XXX.h ====================
+#ifndef XXX_H
+#define XXX_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* ---- 不透明类型(外部无法访问内部字段) ---- */
+typedef struct XXX XXX;
+
+/* ---- 构造/析构 ---- */
+void XXX_init(XXX *me, int param);
+void XXX_deinit(XXX *me);
+
+/* ---- 公开方法(public) ---- */
+int   XXX_getValue(const XXX *me);
+void  XXX_setValue(XXX *me, int v);
+bool  XXX_isReady(const XXX *me);
+void  XXX_reset(XXX *me);
+
+/* ---- 公开常量 ---- */
+#define XXX_MAX_VALUE  255
+
+#endif /* XXX_H */
+```
+
+```c
+// ==================== XXX.c ====================
+#include "XXX.h"
+#include <stdio.h>
+#include <assert.h>
+
+/* ========== private 成员变量 ========== */
+struct XXX {
+    int  value;
+    bool ready;
+};
+
+/* ========== private 静态变量 ========== */
+static int instance_count = 0;
+
+/* ========== private 方法 ========== */
+static void validate(XXX *me) {
+    assert(me->value >= 0 && me->value <= XXX_MAX_VALUE);
+}
+
+/* ========== 构造 / 析构 ========== */
+void XXX_init(XXX *me, int param) {
+    me->value = param;
+    me->ready = true;
+    instance_count++;
+    validate(me);
+}
+void XXX_deinit(XXX *me) {
+    me->ready = false;
+    instance_count--;
+}
+
+/* ========== 公开方法 ========== */
+int  XXX_getValue(const XXX *me) { return me->value; }
+void XXX_setValue(XXX *me, int v) { me->value = v; validate(me); }
+bool XXX_isReady(const XXX *me)   { return me->ready; }
+void XXX_reset(XXX *me)           { me->value = 0; }
+```
+
+### 2.4 实际例子:RingBuffer(环形缓冲区)
+
+这是一个**真正有用**的类,体现封装的全部要点:
+
+```c
+// ==================== RingBuffer.h ====================
+#ifndef RINGBUFFER_H
+#define RINGBUFFER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct RingBuffer RingBuffer;
+
+void RingBuffer_init(RingBuffer *me, uint8_t *buf, int size);
+void RingBuffer_deinit(RingBuffer *me);
+bool RingBuffer_put(RingBuffer *me, uint8_t byte);
+bool RingBuffer_get(RingBuffer *me, uint8_t *byte);
+int  RingBuffer_count(const RingBuffer *me);
+bool RingBuffer_isFull(const RingBuffer *me);
+bool RingBuffer_isEmpty(const RingBuffer *me);
+void RingBuffer_clear(RingBuffer *me);
+
+#endif
+```
+
+```c
+// ==================== RingBuffer.c ====================
+#include "RingBuffer.h"
+#include <string.h>
+
+/* private 成员 */
+struct RingBuffer {
+    uint8_t *buf;
+    int      size;
+    int      head;   // 写指针
+    int      tail;   // 读指针
+};
+
+/* private 方法 */
+static int next_pos(int pos, int size) {
+    return (pos + 1) % size;
+}
+
+/* 构造 */
+void RingBuffer_init(RingBuffer *me, uint8_t *buf, int size) {
+    me->buf  = buf;
+    me->size = size;
+    me->head = 0;
+    me->tail = 0;
+}
+void RingBuffer_deinit(RingBuffer *me) {
+    me->buf = NULL;  // 使用者负责释放 buf
+}
+
+/* 公开方法 */
+bool RingBuffer_put(RingBuffer *me, uint8_t byte) {
+    if (RingBuffer_isFull(me)) return false;
+    me->buf[me->head] = byte;
+    me->head = next_pos(me->head, me->size);
+    return true;
+}
+bool RingBuffer_get(RingBuffer *me, uint8_t *byte) {
+    if (RingBuffer_isEmpty(me)) return false;
+    *byte = me->buf[me->tail];
+    me->tail = next_pos(me->tail, me->size);
+    return true;
+}
+int  RingBuffer_count(const RingBuffer *me) {
+    if (me->head >= me->tail)
+        return me->head - me->tail;
+    return me->size - (me->tail - me->head);
+}
+bool RingBuffer_isFull(const RingBuffer *me) {
+    return next_pos(me->head, me->size) == me->tail;
+}
+bool RingBuffer_isEmpty(const RingBuffer *me) {
+    return me->head == me->tail;
+}
+void RingBuffer_clear(RingBuffer *me) {
+    me->head = me->tail = 0;
+}
+```
+
+```c
+// ==================== main.c ====================
+#include "RingBuffer.h"
+#include <stdio.h>
+
+int main(void) {
+    uint8_t mem[16];
+    RingBuffer rb;
+
+    RingBuffer_init(&rb, mem, sizeof(mem));
+
+    RingBuffer_put(&rb, 'H');
+    RingBuffer_put(&rb, 'i');
+
+    uint8_t ch;
+    while (RingBuffer_get(&rb, &ch)) {
+        putchar(ch);              // → Hi
+    }
+
+    // rb.head = 999;             ← 编译错误!private!
+    RingBuffer_deinit(&rb);
+    return 0;
+}
+```
+
+### 2.5 对照:C++/Java 的封装 vs C
+
+```
+C++                         Java                        C
+──────────────────────────────────────────────────────────────────
+class RingBuffer {          class RingBuffer {          // RingBuffer.h
+private:                    private:                    typedef struct RingBuffer RingBuffer;
+    uint8_t* buf;               byte[] buf;             // RingBuffer.c
+    int head, tail;             int head, tail;          struct RingBuffer { ... };
+public:                     public:                     // RingBuffer.h
+    void put(uint8_t b);        void put(byte b);        void RingBuffer_put(RingBuffer*, uint8_t);
+private:                    private:                    // RingBuffer.c
+    int nextPos(int p);         int nextPos(int p);      static int next_pos(...);
+};
+
+RingBuffer rb;              RingBuffer rb = new...;    RingBuffer rb;
+rb.put('H');                rb.put('H');               RingBuffer_put(&rb, 'H');
+// rb.head                   // rb.head                 // rb.head → 编译错误!
+```
+
+---
+
+## 三、继承:复用公共字段
+
+### 3.1 你遇到的问题
+
+```c
+struct DataPacket {
+    uint32_t src;            // ← 这两个字段每个包类型都有
+    uint32_t dst;            // ←
+    uint32_t seq_num;
+    uint8_t  payload[64];
+};
+struct AckPacket {
+    uint32_t src;            // ← 重复!
+    uint32_t dst;            // ← 重复!
+    uint32_t ack_num;
+    uint32_t window;
+};
+// 改 src 类型?要改两个结构体!
+```
+
+### 3.2 C 的"继承":结构体嵌套
+
+**核心规则**:基类 struct 作为子类 struct 的**第一个成员**。
+
+```c
+// 基类:所有包的公共头
+struct PacketHeader {
+    uint32_t src;
+    uint32_t dst;
+    uint16_t len;
+};
+
+// 子类:数据包("继承" PacketHeader)
+struct DataPacket {
+    struct PacketHeader hdr;   // ★ 第一个成员 = 继承
+    uint32_t seq_num;
+    uint8_t  payload[64];
+};
+
+// 子类:确认包
+struct AckPacket {
+    struct PacketHeader hdr;   // ★ 同样继承
+    uint32_t ack_num;
+    uint32_t window;
+};
+```
+
+### 3.3 内存布局详解(理解了这个就理解了继承)
+
+```c
+struct PacketHeader { uint32_t src; uint32_t dst; uint16_t len; };
+// 偏移:  0            4            8           10
+
+struct DataPacket {
+    struct PacketHeader hdr;   // 偏移 0~11
+    uint32_t seq_num;          // 偏移 12
+    uint8_t  payload[64];      // 偏移 16
+};
+
+// 关键:
+struct DataPacket dp;
+struct PacketHeader *hp = &dp.hdr;   // hp == &dp,地址完全相同!
+```
+
+```
+DataPacket 内存:
+地址: 0x00  0x04  0x08  0x0C  0x10  0x50
+      ┌─────┬─────┬─────┬─────┬──────────┐
+      │ src │ dst │ len │ seq │ payload  │
+      └─────┴─────┴─────┴─────┴──────────┘
+      ↑ hdr 部分 (PacketHeader)       ↑ 子类特有
+      &dp.hdr == &dp  ← 地址相同!
+```
+
+**因为地址相同**,任何需要 `PacketHeader*` 的地方都可以传入 `&dp.hdr`,这就是向上转型(类似 C++ 的 `Derived*` → `Base*`)。
+
+### 3.4 完整模板:Base + Derived
+
+```c
+// ==================== Base.h ====================
+#ifndef BASE_H
+#define BASE_H
+
+typedef struct {
+    int id;
+    char name[32];
+} Base;
+
+void Base_init(Base *me, int id, const char *name);
+void Base_print(const Base *me);
+
+#endif
+```
+
+```c
+// ==================== Base.c ====================
+#include "Base.h"
+#include <stdio.h>
+#include <string.h>
+
+void Base_init(Base *me, int id, const char *name) {
+    me->id = id;
+    strncpy(me->name, name, sizeof(me->name) - 1);
+}
+void Base_print(const Base *me) {
+    printf("[%d] %s", me->id, me->name);
+}
+```
+
+```c
+// ==================== Derived.h ====================
+#ifndef DERIVED_H
+#define DERIVED_H
+
+#include "Base.h"
+
+typedef struct {
+    Base   base;           // ★ 继承:必须是第一个成员
+    int    extra;
+} Derived;
+
+void Derived_init(Derived *me, int id, const char *name, int extra);
+void Derived_print(Derived *me);   // "覆盖"基类方法
+
+#endif
+```
+
+```c
+// ==================== Derived.c ====================
+#include "Derived.h"
+#include <stdio.h>
+
+void Derived_init(Derived *me, int id, const char *name, int extra) {
+    Base_init(&me->base, id, name);   // 先初始化基类
+    me->extra = extra;                  // 再初始化自己的
+}
+
+/* 覆盖:定义同名函数,内部调用基类方法 */
+void Derived_print(Derived *me) {
+    Base_print(&me->base);              // 类似 C++ 的 Base::print()
+    printf(", extra=%d", me->extra);
+}
+```
+
+```c
+// ==================== main.c ====================
+#include "Derived.h"
+
+int main(void) {
+    Derived d;
+    Derived_init(&d, 1, "Alice", 999);
+    Derived_print(&d);            // → [1] Alice, extra=999
+
+    /* 向上转型:Derived* → Base*(安全,因为地址相同) */
+    Base *bp = &d.base;
+    Base_print(bp);               // → [1] Alice
+    return 0;
+}
+```
+
+### 3.5 对照 C++
+
+```cpp
+// C++                               // C
+class Base {                         // Base.h
+public:
+    Base(int id, const char *n);     // Base_init(Base*, int, const char*)
+    void print();                    // Base_print(const Base*)
+private:
+    int id; char name[32];
+};
+
+class Derived : public Base {        // Derived.h: Base base 作为第一成员
+public:
+    Derived(int id, const char *n, int e)
+        : Base(id, n), extra(e) {}   // Derived_init → Base_init(&me->base,...)
+    void print() {                   // Derived_print
+        Base::print();               // Base_print(&me->base)
+        cout << extra;
+    }
+private:
+    int extra;
+};
+
+// 向上转型
+Base *bp = &d;                       // Base *bp = &d.base;
+```
+
+---
+
+## 四、多态:同一个接口,不同的行为
+
+### 4.1 你遇到的问题
+
+```c
+void draw_shape(int type, void *shape) {
+    if (type == 0) {      // Circle
+        Circle *c = (Circle *)shape;
+        draw_circle(c);
+    } else if (type == 1) { // Rect
+        Rect *r = (Rect *)shape;
+        draw_rect(r);
+    }
+    // 每加一种新形状,就要加一个 else if!
+}
+```
+
+### 4.2 解决方案:ops 表(虚函数表)
+
+核心思想:
+1. 定义一个**函数指针结构体**(= C++ 的虚函数表 vtable)
+2. 基类里放一个指向这个结构体的指针(= vptr)
+3. 每个子类提供自己的 ops 表实例
+4. 调用时通过 `obj->ops->method(obj)` 动态分发
+
+### 4.3 完整模板:带虚函数的基类体系
+
+```c
+// ==================== Base.h(带 vtable 的基类模板) ====================
+#ifndef BASE_H
+#define BASE_H
+
+/* ---- 虚函数表定义(相当于 C++ 的 vtable) ---- */
+typedef struct BaseOps {
+    void   (*method1)(void *me, int arg);
+    int    (*method2)(void *me);
+    void   (*destroy)(void *me);      // 可选:析构
+} BaseOps;
+
+/* ---- 基类 ---- */
+typedef struct {
+    const BaseOps *ops;      // ★ vptr:指向子类自己的 ops 表
+    int   id;
+} Base;
+
+/* ---- 统一调度接口(这是你对外调用的入口) ---- */
+void   Base_method1(Base *me, int arg);
+int    Base_method2(Base *me);
+void   Base_destroy(Base *me);
+
+#endif
+```
+
+```c
+// ==================== Base.c(调度实现) ====================
+#include "Base.h"
+#include <assert.h>
+
+void Base_method1(Base *me, int arg) {
+    assert(me->ops && me->ops->method1);   // 类似 C++ 纯虚函数检查
+    me->ops->method1(me, arg);             // ★ 动态分发!
+}
+
+int Base_method2(Base *me) {
+    assert(me->ops && me->ops->method2);
+    return me->ops->method2(me);
+}
+
+void Base_destroy(Base *me) {
+    if (me->ops && me->ops->destroy)
+        me->ops->destroy(me);
+}
+```
+
+```c
+// ==================== Derived.h(子类模板) ====================
+#ifndef DERIVED_H
+#define DERIVED_H
+
+#include "Base.h"
+
+typedef struct {
+    Base   base;             // ★ 继承基类(含 vptr)
+    int    private_data;
+} Derived;
+
+void Derived_init(Derived *me, int id, int data);
+
+#endif
+```
+
+```c
+// ==================== Derived.c(子类实现) ====================
+#include "Derived.h"
+#include <stdio.h>
+
+/* ---- private 方法:子类自己的实现 ---- */
+static void Derived_method1(void *me, int arg) {
+    Derived *self = (Derived *)me;
+    printf("Derived.method1(%d), data=%d\n", arg, self->private_data);
+}
+static int Derived_method2(void *me) {
+    Derived *self = (Derived *)me;
+    return self->private_data * 2;
+}
+
+/* ---- 子类的 ops 表(相当于 C++ 的子类 vtable) ---- */
+static const BaseOps DERIVED_OPS = {
+    .method1 = Derived_method1,
+    .method2 = Derived_method2,
+    .destroy = NULL,
+};
+
+/* ---- 构造:关键 = 绑定 ops ---- */
+void Derived_init(Derived *me, int id, int data) {
+    me->base.ops = &DERIVED_OPS;   // ★ 让 vptr 指向子类的 ops
+    me->base.id  = id;
+    me->private_data = data;
+}
+```
+
+```c
+// ==================== main.c(多态使用) ====================
+#include "Derived.h"
+
+/* 这个函数完全不知道传进来的是哪个子类 */
+void client_code(Base *b) {
+    Base_method1(b, 42);          // → 自动派发到子类实现
+    int r = Base_method2(b);
+    printf("result=%d\n", r);
+}
+
+int main(void) {
+    Derived d;
+    Derived_init(&d, 1, 100);
+
+    client_code((Base *)&d);      // 向上转型 → 多态!
+    return 0;
+}
+```
+
+### 4.4 实际例子:Stream 抽象
+
+不同"流"有相同的读写接口,但底层实现完全不同:
+
+```c
+// ==================== stream.h ====================
+typedef struct StreamOps {
+    int  (*open)(void *me, const char *path);
+    void (*close)(void *me);
+    int  (*read)(void *me, char *buf, int size);
+    int  (*write)(void *me, const char *buf, int size);
+} StreamOps;
+
+typedef struct {
+    const StreamOps *ops;
+    int  fd;
+} Stream;
+
+// 统一接口
+int  Stream_open(Stream *me, const char *path);
+void Stream_close(Stream *me);
+int  Stream_read(Stream *me, char *buf, int size);
+int  Stream_write(Stream *me, const char *buf, int size);
+```
+
+```c
+// ==================== file_stream.c ====================
+#include "stream.h"
+#include <stdio.h>
+
+typedef struct {
+    Stream base;
+    FILE  *fp;
+} FileStream;
+
+static int  fs_open(void *me, const char *path)  { /* fopen */ return 0; }
+static void fs_close(void *me)                    { /* fclose */ }
+static int  fs_read(void *me, char *b, int sz)    { /* fread */ return sz; }
+static int  fs_write(void *me, const char *b, int sz) { /* fwrite */ return sz; }
+
+static const StreamOps FILE_STREAM_OPS = {
+    .open  = fs_open,
+    .close = fs_close,
+    .read  = fs_read,
+    .write = fs_write,
+};
+
+void FileStream_init(FileStream *me) {
+    me->base.ops = &FILE_STREAM_OPS;
+}
+```
+
+```c
+// ==================== null_stream.c ====================
+#include "stream.h"
+
+typedef struct {
+    Stream base;
+} NullStream;
+
+static int  ns_open(void *me, const char *path)  { return 0; }  // 啥也不做
+static void ns_close(void *me)                    { }
+static int  ns_read(void *me, char *b, int sz)    { return 0; }
+static int  ns_write(void *me, const char *b, int sz) { return sz; } // 假装写成功
+
+static const StreamOps NULL_STREAM_OPS = {
+    .open  = ns_open,
+    .close = ns_close,
+    .read  = ns_read,
+    .write = ns_write,
+};
+
+void NullStream_init(NullStream *me) {
+    me->base.ops = &NULL_STREAM_OPS;
+}
+```
+
+```c
+// ==================== main.c ====================
+#include "stream.h"
+#include "file_stream.h"
+#include "null_stream.h"
+
+void copy_data(Stream *in, Stream *out) {
+    // 完全不知道 in/out 是文件、网络还是空流
+    char buf[64];
+    int n;
+    while ((n = Stream_read(in, buf, sizeof(buf))) > 0) {
+        Stream_write(out, buf, n);
+    }
+}
+
+int main(void) {
+    FileStream fs;
+    NullStream ns;
+
+    FileStream_init(&fs);
+    NullStream_init(&ns);
+
+    Stream_open((Stream *)&fs, "input.txt");
+    // NullStream 不需要真正打开
+
+    copy_data((Stream *)&fs, (Stream *)&ns);
+    // 从文件读,写入空流(相当于 /dev/null)
+
+    Stream_close((Stream *)&fs);
+    return 0;
+}
+```
+
+### 4.5 多态的底层本质
+
+```
+C++ 编译后的内存布局:            C 手动布局:
+┌───────────────────────┐       ┌───────────────────────┐
+│ vptr  ─────→ vtable   │       │ ops  ─────→ ops 表    │
+│ fd                    │       │ fd                    │
+│ FILE* (FileStream)    │       │ FILE* (FileStream)    │
+└───────────────────────┘       └───────────────────────┘
+
+C++:   stream->read(buf, n)          → stream->vptr->read(stream, buf, n)
+C:     Stream_read(&fs, buf, n)      → fs.base.ops->read(&fs, buf, n)
+
+完全一致。C++ 编译器帮你写的,C 里你自己写。
+```
+
+---
+
+## 五、向下转型:container_of 原理
+
+### 5.1 问题
+
+你已经通过 `Base *bp = &derived.base;` 向上转型了。现在你想拿回 `Derived *`。
+
+### 5.2 核心宏
+
+```c
+#include <stddef.h>  // 或者自己写
+
+// 计算成员在结构体中的字节偏移
+#define offsetof(TYPE, MEMBER)  ((size_t)&((TYPE *)0)->MEMBER)
+
+// 从成员指针反推结构体指针
+#define container_of(ptr, type, member) ({               \
+    void *__mptr = (void *)(ptr);                        \
+    ((type *)(__mptr - offsetof(type, member)));         \
+})
+```
+
+**原理**:已知结构体某个成员的地址,减去该成员在结构体中的偏移量,就得到结构体的起始地址。
+
+```
+成员地址  →  __mptr
+减去      →  offsetof(type, member)
+得到      →  结构体起始地址
+```
+
+### 5.3 典型用法
+
+```c
+// 场景 1:多态回调中需要子类特有字段
+static int fs_read(void *me, char *buf, int size) {
+    // me 是 Stream*,但我们需要 FileStream 的 FILE*
+    FileStream *self = container_of((Stream *)me, FileStream, base);
+    return fread(buf, 1, size, self->fp);
+}
+
+// 场景 2:Linux 内核 workqueue
+struct my_device {
+    int   irq_num;
+    struct work_struct work;      // 内核结构体内嵌
+};
+static void my_work_handler(struct work_struct *work) {
+    // 内核只给了 work_struct*,要拿回 my_device*
+    struct my_device *dev = container_of(work, struct my_device, work);
+    // 现在可以访问 dev->irq_num
+}
+```
+
+---
+
+## 六、四层架构:工业级项目怎么组织
+
+当你有了多个类(封装)、类之间有继承、有些类需要多态,怎么组织代码?
+
+### 6.1 标准四层
+
+```
+┌─────────────────────────────────────────────┐
+│  app.c          应用层                       │
+│  只操作基类指针,不出现任何硬件关键字           │
+├─────────────────────────────────────────────┤
+│  board_init.c   板级绑定层                    │
+│  实例化具体对象,绑定 ops,暴露全局指针         │
+├─────────────────────────────────────────────┤
+│  xxx_subclass.c 子类实现层                    │
+│  每个子类一个文件:struct + ops 表 + init     │
+├─────────────────────────────────────────────┤
+│  base.h/c       基类定义层                    │
+│  接口 + ops 表类型 + 统一调度函数              │
+└─────────────────────────────────────────────┘
+```
+
+### 6.2 完整四层模板
+
+**第 1 层 — 基类(device.h/.c):**
+
+```c
+// device.h
+#ifndef DEVICE_H
+#define DEVICE_H
+
+typedef struct DeviceOps {
+    int  (*init)(void *me);
+    int  (*read)(void *me, char *buf, int len);
+    int  (*write)(void *me, const char *buf, int len);
+    void (*deinit)(void *me);
+} DeviceOps;
+
+typedef struct {
+    const DeviceOps *ops;
+    char  name[16];
+    int   state;   // 0=closed, 1=ready
+} Device;
+
+int  Device_init(Device *me);
+int  Device_read(Device *me, char *buf, int len);
+int  Device_write(Device *me, const char *buf, int len);
+void Device_deinit(Device *me);
+
+#endif
+```
+
+```c
+// device.c
+#include "device.h"
+#include <assert.h>
+
+int Device_init(Device *me) {
+    assert(me->ops && me->ops->init);
+    return me->ops->init(me);
+}
+int Device_read(Device *me, char *buf, int len) {
+    assert(me->ops && me->ops->read);
+    return me->ops->read(me, buf, len);
+}
+int Device_write(Device *me, const char *buf, int len) {
+    assert(me->ops && me->ops->write);
+    return me->ops->write(me, buf, len);
+}
+void Device_deinit(Device *me) {
+    if (me->ops && me->ops->deinit)
+        me->ops->deinit(me);
+}
+```
+
+**第 2 层 — 子类实现(uart_device.c):**
+
+```c
+// uart_device.h
+#include "device.h"
+typedef struct {
+    Device base;
+    int    uart_num;
+    int    baud;
+} UartDevice;
+
+void UartDevice_init(UartDevice *me, const char *name, int uart_num, int baud);
+```
+
+```c
+// uart_device.c
+#include "uart_device.h"
+#include <stdio.h>
+
+static int  uart_init(void *me)  { printf("UART%d init %d baud\n", ((UartDevice*)me)->uart_num, ((UartDevice*)me)->baud); return 0; }
+static int  uart_read(void *me, char *b, int l) { /* 读 UART 寄存器 */ return l; }
+static int  uart_write(void *me, const char *b, int l) { /* 写 UART 寄存器 */ return l; }
+static void uart_deinit(void *me) { printf("UART deinit\n"); }
+
+static const DeviceOps UART_OPS = {
+    .init   = uart_init,
+    .read   = uart_read,
+    .write  = uart_write,
+    .deinit = uart_deinit,
+};
+
+void UartDevice_init(UartDevice *me, const char *name, int uart_num, int baud) {
+    me->base.ops = &UART_OPS;
+    me->uart_num = uart_num;
+    me->baud = baud;
+}
+```
+
+**第 3 层 — 板级绑定(board_init.c):**
+
+```c
+#include "uart_device.h"
+
+static UartDevice console;
+static UartDevice gps;
+
+Device *g_console;      // 全局指针——暴露给应用层
+Device *g_gps;
+
+void board_init(void) {
+    UartDevice_init(&console, "console", 1, 115200);
+    g_console = (Device *)&console;
+    Device_init(g_console);   // 调用 init ops
+
+    UartDevice_init(&gps, "gps", 2, 9600);
+    g_gps = (Device *)&gps;
+    Device_init(g_gps);
+}
+```
+
+**第 4 层 — 应用层(app.c):**
+
+```c
+// 完全不依赖 UART/GPIO/SPI 等任何硬件关键字
+extern Device *g_console;
+extern Device *g_gps;
+
+void app_main(void) {
+    Device_write(g_console, "Hello\n", 6);
+    char buf[64];
+    int n = Device_read(g_gps, buf, sizeof(buf));
+}
+```
+
+### 6.3 换芯片时的改动
+
+```
+旧芯片                 新芯片
+board_init.c:          board_init.c:
+  UartDevice_init(...)    → 改为新芯片的 UART 驱动
+  g_console = ...         → 指针类型不变,名字不变
+
+app.c: 零改动!          app.c: 零改动!
+```
+
+---
+
+## 七、Linux 内核中的 C-OOP
+
+这不是理论,这是 Linux 内核 4000 万行 C 代码每天都在用的模式。
+
+### 7.1 file_operations — 最经典的 ops 表
+
+```c
+// Linux/include/linux/fs.h
+struct file_operations {
+    loff_t (*llseek)  (struct file *, loff_t, int);
+    ssize_t (*read)   (struct file *, char __user *, size_t, loff_t *);
+    ssize_t (*write)  (struct file *, const char __user *, size_t, loff_t *);
+    int     (*open)   (struct inode *, struct file *);
+    int     (*release)(struct inode *, struct file *);
+    // ... 几十个函数指针
+};
+
+// 每个驱动提供一个自己的 file_operations 实例
+const struct file_operations ext4_file_operations = {
+    .read   = ext4_file_read,
+    .write  = ext4_file_write,
+    .open   = ext4_file_open,
+    // ...
+};
+const struct file_operations socket_file_ops = {
+    .read   = sock_read,
+    .write  = sock_write,
+    // ...
+};
+
+// VFS 统一调用,自动分发
+ssize_t vfs_read(struct file *file, ...) {
+    return file->f_op->read(file, buf, size, pos);  // 多态!
+}
+```
+
+### 7.2 container_of 在内核中的使用
+
+```c
+// Linux 设备驱动标准模式
+struct my_device {
+    int           irq;
+    struct device dev;           // 内核设备模型结构体
+    struct work_struct work;     // 工作队列
+};
+
+// 内核只回调 work 函数,用 container_of 拿回 my_device
+static void my_work_handler(struct work_struct *work) {
+    struct my_device *mdev = container_of(work, struct my_device, work);
+    complete(&mdev->done);
+}
+
+// probe 时注册
+static int my_probe(struct platform_device *pdev) {
+    struct my_device *mdev;
+    mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
+    INIT_WORK(&mdev->work, my_work_handler);
+    platform_set_drvdata(pdev, mdev);
+}
+```
+
+### 7.3 list_head — 侵入式链表
+
+```c
+// Linux/include/linux/types.h
+struct list_head {
+    struct list_head *next, *prev;
+};
+
+// 核心遍历宏
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+// 从节点反查结构体
+#define list_entry(ptr, type, member)  container_of(ptr, type, member)
+
+// 一步到位遍历业务对象
+#define list_for_each_entry(pos, head, member)                  \
+    for (pos = list_entry((head)->next, typeof(*pos), member);  \
+         &pos->member != (head);                                \
+         pos = list_entry(pos->member.next, typeof(*pos), member))
+```
+
+```c
+// 使用例子
+struct my_data {
+    int id;
+    struct list_head node;   // 侵入式节点
+};
+
+LIST_HEAD(data_list);       // 初始化链表头
+
+// 添加
+struct my_data *d = malloc(sizeof(*d));
+d->id = 42;
+list_add_tail(&d->node, &data_list);
+
+// 遍历(无需递归、无需索引)
+struct my_data *pos;
+list_for_each_entry(pos, &data_list, node) {
+    printf("id=%d\n", pos->id);
+}
+```
+
+### 7.4 内核 C-OOP 对照表
+
+| 内核概念 | 你学到的 C-OOP 概念 |
+|---------|-------------------|
+| `struct file_operations` | ops 表(vtable) |
+| `struct i2c_algorithm` | 协议层的 ops 表 |
+| `struct gpio_chip` | 硬件抽象层的 ops 表 |
+| `container_of` | 向下转型 |
+| `list_head` + `list_entry` | 侵入式容器 |
+| `module_init` | 自动注册(`__attribute__((section()))`) |
+| `platform_driver.probe` | 构造函数 + 绑定 |
+| `devm_kzalloc` | 构造中分配资源 |
+
+---
+
+## 八、速查卡(打印贴墙用)
+
+### 8.1 创建一个新类的步骤
+
+```
+1. 复制模板(见 §2.3 XXX.h + XXX.c)
+2. 全局替换 XXX → 你的类名
+3. 在 struct XXX { ... }; 中加你的字段
+4. 实现 init/deinit 和各方法
+5. #include 并使用
+```
+
+### 8.2 C++/Java → C 速查表
+
+```
+C++/Java 概念              →  C 实现
+────────────────────────────────────────────────
+class Student {             →  Student.h + Student.c
+private: int id;            →  struct Student { int id; }; (在 .c 里)
+public: void setId(int);    →  Student.h 中:void Student_setId(Student*, int);
+this->id = id;              →  me->id = id;
+Student(int id, int g)      →  void Student_init(Student*, int, int);
+~Student()                  →  void Student_deinit(Student*);
+继承:class B : public A    →  struct B { A base; int extra; };(A 是第一成员)
+super.method();             →  A_method(&me->base);
+virtual void foo() = 0;     →  ops 表 + assert(ops->foo != NULL)
+多态调用:a->foo()           →  me->ops->foo(me);
+namespace XXX               →  函数前缀 XXX_(例:XXX_init)
+模板:List<T>               →  宏 + void*
+异常 try/catch              →  返回错误码 + assert
+```
+
+### 8.3 关键字用法
+
+| 关键字 | 在 C-OOP 中的角色 |
+|--------|-----------------|
+| `struct` | 定义对象的属性集合(= C++ class 的成员变量) |
+| `static`(文件域) | private 函数/变量(仅本 .c 可见) |
+| `static`(函数内) | 跨调用保持状态的局部变量 |
+| `const` | 只读常量/参数表 |
+| `typedef` | 隐藏 `struct` 关键字,简化类型名 |
+| `extern` | 声明其他文件定义的全局变量 |
+| `void *` | ops 回调中的泛型指针("不知道具体类型,先拿着") |
+| `__attribute__` | GCC 扩展:段控制、对齐、弱符号等 |
+
+### 8.4 常用宏
+
+```c
+/* 成员偏移量 */
+#define offsetof(TYPE, MEMBER)    ((size_t)&((TYPE *)0)->MEMBER)
+
+/* 成员指针 → 结构体指针 */
+#define container_of(ptr, type, member) ({            \
+    void *__mptr = (void *)(ptr);                     \
+    ((type *)(__mptr - offsetof(type, member)));      \
+})
+
+/* 遍历链表 */
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+#define list_entry(ptr, type, member)  container_of(ptr, type, member)
+#define list_for_each_entry(pos, head, member)              \
+    for (pos = list_entry((head)->next, typeof(*pos), member); \
+         &pos->member != (head);                            \
+         pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/* 数组长度 */
+#define ARRAY_SIZE(arr)  (sizeof(arr) / sizeof((arr)[0]))
+
+/* 安全 max/min */
+#define MAX(a,b)  ({ __typeof__(a) _a = (a); __typeof__(b) _b = (b); _a > _b ? _a : _b; })
+#define MIN(a,b)  ({ __typeof__(a) _a = (a); __typeof__(b) _b = (b); _a < _b ? _a : _b; })
+
+/* 位操作 */
+#define BIT(n)          (1UL << (n))
+#define SET_BIT(reg, n) ((reg) |= BIT(n))
+#define CLR_BIT(reg, n) ((reg) &= ~BIT(n))
+
+/* 自动注册(裸机版) */
+#define __init_call __attribute__((section(".initcall")))
+#define MODULE_INIT(fn)  static void (*__init_##fn)(void) __init_call = fn
+```
+
+> 来源:B 站课程《C语言OOP封装完整系列》(500强嵌入式工程师) + Linux 内核源码
+> 关联笔记:[[C++类与对象]] 对比 C++ class 底层原理

+ 18 - 26
X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/16-内存管理.md

@@ -6,7 +6,6 @@ author: "尚硅谷研究院"
 date: 2026-07-17
 created: 2026-07-17
 ---
-
 # FreeRTOS 内存管理
 
 > **用生活理解**:动态内存像租房子——heap_1 是只租不退的宿舍(简单粗暴),heap_2 是随意退租但不打扫的房间(会碎片),heap_4 是退租时帮你合并相邻空房的管家(推荐),heap_5 是能跨多个不同地段管理房源的大中介。
@@ -18,6 +17,7 @@ created: 2026-07-17
 FreeRTOS 在创建任务、队列、信号量等内核对象时,支持**动态创建**和**静态创建**两种方式。动态方式更灵活(调用 `pvPortMalloc` 自动从堆中分配),静态方式则需要用户预先分配内存。
 
 标准 C 库的 `malloc()` / `free()` 在嵌入式系统中存在以下问题:
+
 - 并非所有嵌入式平台都可用
 - 占用宝贵的代码空间
 - 线程不安全
@@ -27,13 +27,13 @@ FreeRTOS 在创建任务、队列、信号量等内核对象时,支持**动态
 
 ### 5 种 Heap 算法对比
 
-| 算法 | 策略 | 释放 | 碎片 | 适用场景 |
-|------|------|------|------|---------|
-| **heap_1** | 简单数组分配 | ❌ 不支持 | 无碎片 | 从不删除任务/队列的简单应用 |
-| **heap_2** | 最佳适应(Best-fit)链表 | ✅ | ❌ 会碎片 | 动态创建/删除但大小固定的场景 |
-| **heap_3** | 包装标准 malloc/free | ✅ | 取决于 C 库 | 需要线程安全的 malloc |
-| **heap_4** | 首次适应(First-fit)+合并相邻块 | ✅ | 碎片少 | **默认推荐** |
-| **heap_5** | 同 heap_4 | ✅ | 碎片少 | 多个非连续 RAM 区域 |
+| 算法             | 策略                             | 释放      | 碎片        | 适用场景                      |
+| ---------------- | -------------------------------- | --------- | ----------- | ----------------------------- |
+| **heap_1** | 简单数组分配                     | ❌ 不支持 | 无碎片      | 从不删除任务/队列的简单应用   |
+| **heap_2** | 最佳适应(Best-fit)链表         | ✅        | ❌ 会碎片   | 动态创建/删除但大小固定的场景 |
+| **heap_3** | 包装标准 malloc/free             | ✅        | 取决于 C 库 | 需要线程安全的 malloc         |
+| **heap_4** | 首次适应(First-fit)+合并相邻块 | ✅        | 碎片少      | **默认推荐**            |
+| **heap_5** | 同 heap_4                        | ✅        | 碎片少      | 多个非连续 RAM 区域           |
 
 ### 工作原理
 
@@ -49,11 +49,11 @@ FreeRTOS 在创建任务、队列、信号量等内核对象时,支持**动态
 
 ### 核心API
 
-| API | 描述 |
-|-----|------|
+| API                                        | 描述               |
+| ------------------------------------------ | ------------------ |
 | `void *pvPortMalloc(size_t xWantedSize)` | 申请内存,返回指针 |
-| `void vPortFree(void *pv)` | 释放内存 |
-| `size_t xPortGetFreeHeapSize(void)` | 获取当前空闲堆大小 |
+| `void vPortFree(void *pv)`               | 释放内存           |
+| `size_t xPortGetFreeHeapSize(void)`      | 获取当前空闲堆大小 |
 
 ## 实验
 
@@ -147,29 +147,21 @@ void task1(void *pvParameters)
 
 ## 核心函数速查表
 
-| API | 参数 | 返回值 | 说明 |
-|-----|------|--------|------|
-| `pvPortMalloc(xWantedSize)` | xWantedSize=请求字节数 | 成功返回指针,失败返回 NULL | 从 FreeRTOS 堆中分配内存 |
-| `vPortFree(pv)` | pv=要释放的内存指针 | 无 | 释放内存回堆 |
-| `xPortGetFreeHeapSize()` | 无 | size_t 空闲字节数 | 获取当前堆空闲大小 |
-| `xPortGetMinimumEverFreeHeapSize()` | 无 | size_t 历史最小空闲 | 追踪最小剩余堆(需 `configUSE_TRACE_FACILITY=1`) |
+| API                                   | 参数                   | 返回值                      | 说明                                               |
+| ------------------------------------- | ---------------------- | --------------------------- | -------------------------------------------------- |
+| `pvPortMalloc(xWantedSize)`         | xWantedSize=请求字节数 | 成功返回指针,失败返回 NULL | 从 FreeRTOS 堆中分配内存                           |
+| `vPortFree(pv)`                     | pv=要释放的内存指针    | 无                          | 释放内存回堆                                       |
+| `xPortGetFreeHeapSize()`            | 无                     | size_t 空闲字节数           | 获取当前堆空闲大小                                 |
+| `xPortGetMinimumEverFreeHeapSize()` | 无                     | size_t 历史最小空闲         | 追踪最小剩余堆(需`configUSE_TRACE_FACILITY=1`) |
 
 > **注意**:`xPortGetFreeHeapSize()` 只在 heap_1/2/4/5 中有效(heap_3 包装 C 库 malloc,无法统计 FreeRTOS 堆)。
 
 ## 常见问题与避坑
 
 1. **默认使用 heap_4**:移植 FreeRTOS 时必须从 `MemMang/` 中选择一个 heap 文件加入工程(通常选 `heap_4.c`),否则链接报错。
-
 2. **`configTOTAL_HEAP_SIZE` 不够会导致创建任务失败**:任务栈、TCB 等全部从堆中分配。堆太小 → `pvPortMalloc` 返回 NULL → `xTaskCreate` 返回 `errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY`。
-
 3. **`pvPortMalloc` 返回 NULL 要处理**:申请失败不会崩溃,但后续使用 NULL 指针会导致 HardFault。务必检查返回值。
-
 4. **释放野指针会导致 HardFault**:`vPortFree` 必须传入 `pvPortMalloc` 返回的有效指针。释放栈上变量或已释放的指针会造成不可预知的错误。
-
 5. **不能在中断中调用 `pvPortMalloc` / `vPortFree`**:这些函数不是中断安全的。在中断中需要分配内存时,使用中断安全版的队列/信号量函数替代。
-
 6. **heap_4 的内存碎片虽然少但仍有**:长期频繁分配/释放不同大小的内存仍会导致外部碎片。定期用 `xPortGetMinimumEverFreeHeapSize()` 监控堆健康状态。
-
 7. **heap_5 需要额外初始化**:使用前必须调用 `vPortDefineHeapRegions()` 指定每个 RAM 区域的起始地址和大小。
-
-![Heap 算法对比](./assets/heap_comparison.png)

+ 9 - 0
X-Knowledge-Base/wiki/index.md

@@ -67,3 +67,12 @@ Wiki 页面(高级篇 + 扩展篇 — 含代码准确性审计):
 - [[Note 19 BKP RTC]] — BKP 备份寄存器与 RTC
 - [[Note 20 Watchdog]] — 看门狗 IWDG/WWDG
 - [[source-stm32-lower-audit]] — 代码准确性审计报告
+
+## C 语言面向对象编程
+
+> 来源:`raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/`
+
+在纯 C 中实现封装、继承、多态三大 OOP 特性,对标 Linux 内核与工业嵌入式实践。
+
+- [[source-c-oop]] — 原始资料摘要
+- `raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/c-oop.md` — 完整指南(含 C vs C++/Java 详细对比)

+ 20 - 0
X-Knowledge-Base/wiki/log.md

@@ -161,3 +161,23 @@ type: log
     实现计划:`docs/superpowers/plans/2026-07-17-freertos-ingest.md`
 
     更新 `wiki/source-freertos.md`、`wiki/log.md`
+
+## 2026-07-23
+
+- `wiki`: 新增 C 语言 OOP 完整指南
+
+   原始资料:`raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/`
+   摘要页面:`wiki/source-c-oop.md`
+   指南页面:`wiki/c-oop.md`
+   学习副本:`raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/c-oop.md`
+
+   内容覆盖:
+   - 基于 struct + 函数指针的封装/继承/多态实现
+   - static/const/typedef/extern/inline 关键字在 C-OOP 中的用法
+   - container_of / offsetof 宏原理与实现
+   - Linux 内核 file_operations / list_head / module_init 模式对照
+   - 四层架构(基类/子类/板级绑定/应用层)
+   - C vs C++/Java 全面对比(Student 类完整例子 + private/public 映射)
+   - 完整代码示例与学习路径
+
+- `lint`: 移动 c-oop.md 到 raw/,删除 wiki/c-oop.md,更新引用路径

+ 86 - 0
X-Knowledge-Base/wiki/source-c-oop.md

@@ -0,0 +1,86 @@
+---
+tags: [source-summary]
+type: source
+source: "C语言OOP封装完整系列 (B站视频课程)"
+author: "500强11年嵌入式工程师"
+date: 2026-05-05
+url: ""
+created: 2026-07-23
+---
+
+# C语言OOP封装完整系列 — 资料摘要
+
+> 原始资料:`raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/`,包含 PDF 笔记、PPTX 和 DOCX 三份文件。
+> 主题:用纯 C 语言实现面向对象编程的封装、继承、多态三大特性,最终构建嵌入式四层架构。
+
+## 核心脉络
+
+整个系列从**一个 LED 驱动**出发,逐步演化出完整的 C-OOP 架构:
+
+```text
+原始重复代码
+  → struct 封装(数据结构化)
+  → static 信息隐藏(模块内聚)
+  → 头文件/源文件分离(接口与实现隔离)
+  → 模块前缀规范(命名空间模拟)
+  → init/deinit 生命周期(构造函数/析构函数模拟)
+  → 基类嵌套(继承模拟)
+  → 函数指针传参(策略模式)
+  → ops 操作表(虚函数表模拟)
+  → vptr 嵌入对象(多态就绪)
+  → container_of 向下转型
+  → 四层架构(基类/子类/板级绑定/应用)
+  → module_init 自动注册(Linux 内核风格)
+```
+
+## 关键知识点索引
+
+| 知识点 | 核心作用 | 对应 C 语法/模式 |
+|--------|---------|-----------------|
+| 封装 | 数据+操作绑定,隐藏实现细节 | `struct` 组织数据,`static` 限制作用域 |
+| 继承 | 复用公共字段和行为 | 基类 `struct` 作为子类**第一个成员**嵌套 |
+| 多态 | 同一接口不同实现 | 函数指针 `void (*on)(base*)` + vtable |
+| 信息隐藏 | 阻止外部直接访问数据 | `static` 函数+变量,头文件只暴露接口 |
+| 命名空间 | 避免符号冲突 | 模块前缀 `led_`、`gpio_` |
+| 生命周期 | 规范化初始化和清理 | `init()` / `deinit()` 配对 |
+| 向上转型 | 子类指针→基类指针 | 直接取 `&obj.base` |
+| 向下转型 | 基类指针→子类指针 | `container_of` 宏 |
+| 虚函数表 | 运行时多态调度 | `struct LedOps` 存函数指针 + 对象内嵌 `ops*` |
+| 纯虚函数 | 强制子类实现 | `assert(me->ops->on != NULL)` |
+| 延迟绑定 | 运行时决定调用哪个函数 | 函数指针赋值 + 间接调用 |
+| 自动注册 | 模块无需修改主函数 | `__attribute__((section()))` + 链接脚本 |
+
+## 四层架构
+
+```
+第1层: led_base.h/c       — 基类 (name, state, ops*)
+第2层: led_gpio.c/pwm.c   — 子类实现 (嵌套 base + 私有数据)
+第3层: board_init.c        — 板级绑定 (实例化+初始化+暴露全局指针)
+第4层: app.c               — 应用层 (只通过全局指针操作)
+```
+
+## Linux 内核对应
+
+- `struct file_operations` = LedOps(操作表)
+- `container_of` = 向下转型宏
+- `module_init` = `__attribute__((section(".initcall6.init")))`
+- `i2c_algorithm` = 协议层 ops
+- `gpio_chip` = 硬件抽象 ops
+
+## 关键宏
+
+```c
+// 计算成员在结构体中的偏移量(字节数)
+#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
+
+// 从成员指针反推结构体指针
+#define container_of(ptr, type, member) ({ \
+    void *__mptr = (void *)(ptr); \
+    ((type *)(__mptr - offsetof(type, member))); })
+```
+
+## 参考关联
+
+- `raw/Joplin/嵌入式+Linux/C语言OOP封装完整系列/c-oop.md` — 完整指南
+- [[继承与多态]] — C++ 的 OOP 实现对比
+- [[C++类与对象]] — C++ class 底层原理