C语言实现-----面向对象编程

一、把"数据"和"能作用在这份数据上的行为(函数)"打包放在一起

C语言中使用"结构体 + 函数指针"来模拟面向对象编程(OOP)的"对象 + 方法"

是C语言中最经典、最常见的"伪OOP"写法之一。

这种写法在很多嵌入式系统、游戏引擎、图形库、驱动程序、GUI框架中都被广泛使用(GTK、libuv、SDL、Linux内核的部分模块等都大量使用类似手法)。

核心思想

把"数据"和"能作用在这份数据上的行为(函数)"打包放在一起。

c 复制代码
typedef struct {
    // 数据成员
    int x;
    int y;
    
    // 方法(函数指针)
    void (*move)(void* self, int dx, int dy);   // 第一个参数通常放自己
    void (*print)(const void* self);
    double (*distance_to_origin)(const void* self);
} Point;

最常见的几种写法对比(由简到复杂)

写法编号 风格 self 参数写法 推荐场景 易读性 维护性
1 显式传 self void (*func)(void* self, ...) 初学者、教学 ★★★☆☆ ★★★☆☆
2 用宏隐藏 self #define this self 个人项目、追求简洁 ★★★★☆ ★★☆☆☆
3 强类型 self(推荐) void (*func)(This* self, ...) 中大型项目、库设计 ★★★★★ ★★★★★
4 带继承(虚函数表) vtable + 结构体开头 需要多态的复杂系统 ★★★☆☆ ★★★★☆

下面我们用最推荐的第3种写法(强类型 self)来完整举例:

推荐写法示例(2024-2025年主流做法)

c 复制代码
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

// 前向声明
typedef struct Point Point;

// ==================== 1. 定义"类"(结构体) ====================
struct Point {
    // 数据部分
    float x;
    float y;

    // 方法表(函数指针)
    void    (*move)(Point* self, float dx, float dy);
    void    (*print)(const Point* self);
    float   (*distance_to)(const Point* self, const Point* other);
    void    (*destroy)(Point* self);   // 类似析构函数
};


// ==================== 2. 方法实现 ====================

static void point_move(Point* self, float dx, float dy) {
    self->x += dx;
    self->y += dy;
}

static void point_print(const Point* self) {
    printf("Point(%.2f, %.2f)\n", self->x, self->y);
}

static float point_distance_to(const Point* self, const Point* other) {
    float dx = self->x - other->x;
    float dy = self->y - other->y;
    return sqrtf(dx*dx + dy*dy);
}

static void point_destroy(Point* self) {
    // 如果有动态分配的成员,这里释放
    // 这里只是示例,实际可以 free(self) 如果是堆上创建的
    printf("Point at %p destroyed\n", (void*)self);
    // free(self);   // 如果是用 malloc 创建的才需要
}


// ==================== 3. 构造函数(工厂函数) ====================

Point* point_new(float x, float y) {
    Point* p = malloc(sizeof(Point));
    if (!p) return NULL;

    // 初始化数据
    p->x = x;
    p->y = y;

    // 绑定方法(最关键一步)
    p->move        = point_move;
    p->print       = point_print;
    p->distance_to = point_distance_to;
    p->destroy     = point_destroy;

    return p;
}


// ==================== 4. 使用方式 ====================

int main() {
    Point* p1 = point_new(3, 4);
    Point* p2 = point_new(0, 0);

    if (!p1 || !p2) {
        printf("内存分配失败\n");
        return 1;
    }

    p1->print(p1);                // Point(3.00, 4.00)
    p1->move(p1, 1, -2);
    p1->print(p1);                // Point(4.00, 2.00)

    printf("距离原点: %.2f\n", p1->distance_to(p1, p2));

    p1->destroy(p1);
    p2->destroy(p2);

    free(p1);
    free(p2);

    return 0;
}

更简洁但牺牲类型安全的写法(风格1)

很多人教学时会这样写(初学者常见):

c 复制代码
typedef struct {
    int x, y;
    void (*move)(void* self, int dx, int dy);
    void (*show)(void* self);
} Shape;

void shape_move(void* self, int dx, int dy) {
    Shape* s = (Shape*)self;
    s->x += dx;
    s->y += dy;
}

带"继承"与多态的进阶写法(简版)

c 复制代码
typedef struct {
    // 虚函数表必须放在最前面
    struct {
        void (*draw)(void* self);
        void (*move)(void* self, int dx, int dy);
    } vtable;

    int x, y;
    // ... 公共数据
} Shape;

typedef struct {
    Shape base;
    int radius;
} Circle;

void circle_draw(void* self) {
    Circle* c = self;
    printf("Circle at (%d,%d) r=%d\n", c->base.x, c->base.y, c->radius);
}

希望这些例子能帮忙清晰地理解"结构体+函数指针"模拟OOP的各种写法梯度。

可以考虑最想深入哪一种风格?

(简单版 / 推荐强类型版 / 带继承的多态版 / 其他变种)



八、self风格:#define this self,

#define this self 是一个宏定义 ,作用是把代码中所有的 this 替换成 self

基本语法

c 复制代码
#define 宏名 替换内容

预处理器在编译前会把源码中所有出现 宏名 的地方,原样替换成 替换内容


#define this self 的具体含义

c 复制代码
#define this self

这行代码让你可以用 this 这个关键字风格的写法来代替 self

常见于用 C 模拟面向对象编程时:

c 复制代码
#define this self

typedef struct {
    int x;
    int y;
} Point;

void Point_move(Point *self, int dx, int dy) {
    this->x += dx;   // 预处理后变成 self->x += dx
    this->y += dy;   // 预处理后变成 self->y += dy
}

对比没有这个宏的写法:

c 复制代码
void Point_move(Point *self, int dx, int dy) {
    self->x += dx;
    self->y += dy;
}

两者编译结果完全一样,只是写法风格不同。


常见使用场景

场景 说明
模拟 C++ 的 this 让 C 代码更像面向对象风格
跨语言风格统一 团队习惯用 this,但底层参数命名为 self
嵌入式 / 框架代码 一些框架(如 GObject)用 self,宏做兼容层

注意事项

  • 这是纯文本替换 ,没有类型检查,预处理阶段完成,编译器看不到 this
  • C++ 中 this真正的关键字 ,不能这样 #define(会报错)
  • 滥用可能降低代码可读性,建议团队内统一规范


九、补充信息

GTKGIMP Toolkit (GIMP 工具包)的简称,是一个免费开源的跨平台图形用户界面(GUI)工具包。它主要用于创建桌面应用程序的图形界面,从简单的工具软件到完整的应用套件都可以使用。

  • 核心特点:提供完整的 UI 组件(窗口、按钮、菜单、工具栏等),支持主题定制和原生外观;基于 GLib 构建,采用面向对象的 C API;跨平台(Linux、Windows、macOS);有 Python、JavaScript、C++、Rust 等多种语言绑定。
  • 当前版本(2026 年 4 月):稳定版 GTK 4.22.2(GTK 3 已进入维护阶段)。
  • 许可:GNU Lesser General Public License (LGPL)。
  • 主要应用:GNOME 桌面环境的核心工具包,广泛用于 Linux 桌面应用(如 GIMP、Inkscape、Evolution、Transmission、HandBrake 等)。它特别适合需要美观、稳定且与 Linux 原生集成良好的 GUI 程序。

libuv 是一个多平台异步 I/O 支持库,专注于提供高效的事件循环和非阻塞 I/O 操作。它是 Node.js 的底层核心引擎之一,但也可独立用于其他项目。

  • 核心特点:基于事件循环(event loop)的异步编程模型;支持异步 TCP/UDP 网络、文件系统 I/O、定时器、子进程、DNS 等;使用平台原生机制(如 Linux epoll、macOS kqueue、Windows IOCP、Linux io_uring)实现高性能;纯 C 编写,轻量级且跨平台。
  • 与 Node.js 的关系:Node.js 的异步能力主要由 libuv 提供(V8 引擎负责 JavaScript 执行,libuv 负责底层 I/O)。
  • 许可:MIT 许可。
  • 主要应用:服务器端网络应用、实时系统、游戏服务器、任何需要高并发异步 I/O 的 C/C++ 项目。常被用于构建类似 Node.js 的异步框架或嵌入式高性能服务。

SDLSimple DirectMedia Layer ,简单直接媒体层)是一个跨平台的低级多媒体开发库,专门为游戏、模拟器和多媒体软件提供对硬件的直接访问。

  • 核心特点:提供音频、键盘、鼠标、摇杆、手柄等输入设备的低级访问;支持 2D/3D 图形渲染(OpenGL、Direct3D、Vulkan);跨平台(Windows、macOS、Linux、iOS、Android);用 C 编写,可直接与 C++ 使用,也有 C#、Python 等绑定。
  • 当前版本(2026 年 1 月):SDL 3.4(新增 GPU 与 2D 渲染互操作、本地 PNG 支持、更好的 Emscripten/Web 支持、Steam Controller 等新特性)。
  • 许可:zlib 许可(非常宽松)。
  • 主要应用:游戏开发(Valve 游戏、Humble Bundle 许多独立游戏)、视频播放器、模拟器(如 RetroArch)、VR/AR 工具、任何需要高效硬件访问的跨平台多媒体程序。

简单对比(便于理解三者的定位):

  • GTK:高级 GUI 框架 → 做桌面应用界面。
  • libuv:底层异步 I/O 引擎 → 做高性能网络/服务器后端。
  • SDL:低级多媒体/游戏库 → 做游戏、音视频、硬件直连的程序。

三者都是开源、跨平台且广泛使用的 C 语言库,常被开发者组合使用(如用 SDL 做游戏渲染 + GTK 做设置界面,或在 Node.js 项目里直接调用 libuv)。如果你需要某个库的具体安装、示例代码或教程,可以告诉我,我再详细展开!

相关推荐
Kethy__2 小时前
计算机中级-数据库系统工程师-数据结构-树与二叉树(2)
数据结构·数据库·软考··计算机中级
不爱吃糖的程序媛2 小时前
鸿蒙PC tiny-AES-c三方库适配实践
c语言·华为·harmonyos
HABuo2 小时前
【linux线程(三)】生产者消费者模型(条件变量阻塞队列版本、信号量环形队列版本)详细剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
bestblueheart2 小时前
C语言怎么学?系统学习路线图分享
c语言·指针·计算机基础·学习路线·编程思想
Dr.F.Arthur2 小时前
我的算法笔记——哈希表篇
数据结构·笔记·散列表
漂流瓶jz2 小时前
UVA-11846 找座位 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·排序算法·深度优先·aoapc·算法竞赛入门经典·uva
RFCEO4 小时前
C语言逆向学习基础课 第1课:数组越界与指针操作基础陷阱
c语言·解引用校验·safe_free宏·悬空指针
东北甜妹5 小时前
MYSQL 总结
数据结构
北顾笙9805 小时前
day12-数据结构力扣
数据结构·算法·leetcode