用 C 语言实现面向对象:pThis 模式技术解析

用 C 语言实现面向对象:pThis 模式技术解析

一、引言

在嵌入式、汽车电子、驱动开发等场景中,工程约束往往要求使用纯 C 语言,而业务又希望具备封装、多实例、多态 等面向对象能力。一种成熟做法是:用结构体 + 函数指针 + 显式"当前对象"参数 在 C 中模拟类和 this 指针,该参数通常命名为 pThis

本文从技术方法实现过程 出发,用通用示例对比 C++C 两种实现方式,并配合图示说明,不依赖任何具体业务代码。


二、概念对应关系

概念 C++ C(pThis 模式)
class 含数据与函数指针的 struct
对象 类实例 struct 实例
当前对象 隐式 this 显式参数 pThis
成员函数 类内方法 首参为 pThis 的 C 函数
多态 virtual 与虚表 结构体内函数指针,初始化时绑定
构造 构造函数 XXX_Init(pThis, ...)

三、示例场景说明

为便于说明,下文统一用一个计数器对象作为示例:

  • 内部维护一个整型计数值;
  • 提供:初始化、加一、取当前值、复位;
  • 支持多个计数器实例,各自独立。

下面分别用 C++ 和 C(pThis)实现同一逻辑。


四、C++ 实现

4.1 类定义

cpp 复制代码
// counter.hpp
#ifndef COUNTER_HPP
#define COUNTER_HPP

class Counter {
public:
    Counter(const char* name);   // 构造

    void   init(const char* name);
    void   increment();           // 加一
    int    getValue() const;      // 取值
    void   reset();               // 复位

private:
    const char* name_;            // 对象名称
    int         value_;           // 计数值
};

#endif

4.2 实现

cpp 复制代码
// counter.cpp
#include "counter.hpp"

Counter::Counter(const char* name) : name_(name), value_(0) {}

void Counter::init(const char* name) {
    name_  = name;
    value_ = 0;
}

void Counter::increment() {
    value_++;   // 隐式使用 this->value_
}

int Counter::getValue() const {
    return value_;   // 隐式使用 this->value_
}

void Counter::reset() {
    value_ = 0;
}

// 使用:多实例,各自独立
void example_cpp() {
    Counter c1("A");
    Counter c2("B");

    c1.increment();
    c1.increment();
    c2.increment();

    // c1.getValue() == 2, c2.getValue() == 1
}

4.3 类图

成员类型 成员名称 类型 说明
私有 name_ const char* 对象名称
私有 value_ int 计数值
公有 init(name) void 初始化方法
公有 increment() void 加一方法(内部通过 this->value_ 访问)
公有 getValue() int 获取当前值
公有 reset() void 复位方法

五、C 实现(pThis 模式)

5.1 设计思路

  • "类" :定义一个 struct,包含数据成员和可选的一组函数指针(用于多态或统一接口)。
  • "当前对象" :不依赖编译器,由调用方在每次调用时传入,即第一个参数 pThis
  • "构造" :提供 Counter_Init(pThis, name),对 pThis 指向的实例做初始化,必要时挂接函数指针。

这样,同一套 C 函数可服务多个对象,仅通过传入不同的 pThis 区分。

5.2 头文件:结构体与接口

c 复制代码
/* counter.h */
#ifndef COUNTER_H
#define COUNTER_H

typedef struct CounterObj CounterObj;

struct CounterObj {
    const char* name;
    int         value;

    /* 可选:函数指针表示"方法",便于多态或统一调用 */
    void (*increment)(CounterObj* pThis);
    int  (*getValue)(CounterObj* pThis);
    void (*reset)(CounterObj* pThis);
};

int  Counter_Init(CounterObj* pThis, const char* name);
void Counter_Increment(CounterObj* pThis);
int  Counter_GetValue(CounterObj* pThis);
void Counter_Reset(CounterObj* pThis);

#endif

5.3 实现文件:所有"方法"显式带 pThis

c 复制代码
/* counter.c */
#include "counter.h"

static void do_increment(CounterObj* pThis) {
    pThis->value++;
}

static int do_get_value(CounterObj* pThis) {
    return pThis->value;
}

static void do_reset(CounterObj* pThis) {
    pThis->value = 0;
}

int Counter_Init(CounterObj* pThis, const char* name) {
    if (!pThis) return -1;
    pThis->name     = name;
    pThis->value    = 0;
    pThis->increment = do_increment;
    pThis->getValue  = do_get_value;
    pThis->reset     = do_reset;
    return 0;
}

void Counter_Increment(CounterObj* pThis) {
    if (pThis) pThis->value++;
}

int Counter_GetValue(CounterObj* pThis) {
    return pThis ? pThis->value : 0;
}

void Counter_Reset(CounterObj* pThis) {
    if (pThis) pThis->value = 0;
}

/* 使用:多实例,同一套代码,不同 pThis */
void example_c(void) {
    CounterObj c1, c2;

    Counter_Init(&c1, "A");
    Counter_Init(&c2, "B");

    Counter_Increment(&c1);
    Counter_Increment(&c1);
    Counter_Increment(&c2);

    /* 也可通过函数指针调用(多态/表驱动) */
    c1.increment(&c1);
    /* c1.value == 3, c2.value == 1 */
}

5.4 C 侧"类"与 pThis 关系

C 侧用结构体表示"类",所有"方法"的第一个参数都是 pThis,表示当前操作的对象。对应关系如下:

成员类型 成员名 说明
数据 name 对象名称
数据 value 计数值
函数指针 increment(pThis) 加一,首参为当前对象指针
函数指针 getValue(pThis) 取值,首参为当前对象指针
函数指针 reset(pThis) 复位,首参为当前对象指针

结构体形态可理解为:

复制代码
CounterObj
├── name, value          (数据)
└── increment, getValue, reset   (函数指针,均带 pThis 参数)

六、pThis 在调用链中的角色

无论是 C++ 的 this 还是 C 的 pThis,在调用链中的作用都是:标识并传递"当前对象"。C++ 由编译器隐式传递,C 由开发者显式传递。下图表示一次"加一"调用的过程。
Counter_Increment() CounterObj 实例 (c1 / c2) 调用方 Counter_Increment() CounterObj 实例 (c1 / c2) 调用方 模拟 this 指针\npThis 指向对象实例 调用 Counter_Increment(&c1) 传入 pThis = &c1 pThis->>value++ 返回 调用完成


七、实现过程小结

7.1 C 侧实现步骤

  1. 定义"类"结构体

    包含数据成员;若需要多态或统一接口,再增加函数指针成员。

  2. 约定"方法"形式

    所有操作该对象的函数,第一个参数为 XXXObj* pThis,并在函数体内通过 pThis->成员 访问数据。

  3. 提供 Init

    实现 XXX_Init(pThis, ...),对 pThis 指向的实例赋初值,必要时给函数指针赋值。

  4. 多实例使用

    声明多个 struct 实例,分别调用 Init(&obj1, ...)Init(&obj2, ...),之后所有接口都传入对应的 &obj1 / &obj2 作为 pThis

7.2 流程概览(Mermaid)

定义 struct + 数据/函数指针
实现带 pThis 的 C 函数
实现 Init 绑定函数指针
多实例 Init 不同 pThis
业务调用时传入对应 pThis


八、C 与 C++ 实现对比

维度 C++ C(pThis)
当前对象 编译器隐式 this 显式参数 pThis
多实例 多个类实例 多个 struct,传不同 pThis
多态 virtual + 虚表 结构体内函数指针,Init 时绑定
封装 private / 命名空间 static 函数 + 仅暴露头文件 API
可读性 更贴近"对象"思维 需约定"首参即 pThis"
典型场景 允许 C++ 的项目 纯 C、MISRA-C、传统固件

九、适用场景与注意点

适合采用 pThis 模式的情况:

  • 需要多个逻辑相同、数据独立的实例;
  • 希望用函数指针做表驱动或策略替换(类似虚函数);
  • 项目仅允许使用 C;
  • 希望统一风格:所有"对象方法"首参为 pThis

注意点:

  • 调用时务必传入有效指针,避免空指针或野指针;
  • 多线程场景下,若对象被多线程共享,需自行加锁保护;
  • 函数指针在 Init 时绑定,避免未初始化即通过函数指针调用。

十、总结

  • C++ 通过 class 和隐式 this 表达"当前对象",语法自然。
  • C 通过 struct + 函数指针 + 显式 pThis 达到相同效果:同一套逻辑、多实例、可多态。

pThis 理解为"C 里的 this",并按照"定义结构体 → 实现带 pThis 的函数 → Init 绑定 → 多实例传不同 pThis"的过程实现,即可在纯 C 环境中复用面向对象的设计思路,而不依赖具体业务代码。本文提供的计数器示例与图示可直接用于理解与方法迁移。

相关推荐
爱编码的小八嘎2 小时前
C语言完美演绎3-13
c语言
自信150413057592 小时前
数据结构之实现链式结构二叉树
c语言·数据结构·算法
badhope2 小时前
C语言二级考点全解析与真题精讲
c语言·开发语言·c++·人工智能·python·microsoft·职场和发展
二年级程序员4 小时前
排序(五)“计数排序” 与 “各排序实际用时测量”
c语言·算法·排序算法
bkspiderx5 小时前
MQTT 开源库:Eclipse Paho C 详解,特性、交叉编译与实战示例
c语言·mqtt·开源·eclipse paho c
djarmy5 小时前
量子计算必然走向边缘+终端+云端的分布式架构,而oh是目前唯一面向全场景的分布式
c语言
巧克力味的桃子5 小时前
最长连续因子问题 - C语言学习笔记
c语言·笔记·学习
Genevieve_xiao5 小时前
【写给新人】在 vscode 中配置适用于算法竞赛背景的 c/c++
c语言·vscode·算法
Z9fish6 小时前
sse哈工大C语言编程练习44
c语言·c++·算法