C语言模拟对象、方法:“函数指针+结构体“复用函数指针指向的函数体

preface

c语言的函数指针+结构体 模拟对象和方法,复用函数指针指向的函数体

助手思考过程

(本轮为直接概念问答,未触发独立的 extended-thinking 块;回答基于对 C 语言对象模拟机制的直接组织:先给核心结论「复用同一份函数体」,再用可运行代码证明 a.bark == b.bark,然后强调 self 参数不可省,最后升级到 vtable 的工程做法,并关联到本仓库 业务目录内存表 引擎复用思路。)

助手回复

核心结论

用「结构体存数据 + 函数指针存方法」模拟对象时:

  • 函数体(代码)只有一份 ,存在于代码段(.text),被所有"对象"共享;
  • 每个对象各有一份数据(结构体实例,在堆/栈上);
  • 函数指针只是指向那唯一一份函数体的地址,不同对象的同名指针通常指向同一个函数。

这和 C++ 的成员函数机制其实一样:C++ 的成员函数也是一份代码,靠隐藏的 this 指针区分是哪个对象。

用代码看清楚

c 复制代码
typedef struct Dog {
    char name[32];
    void (*bark)(struct Dog *self);   // 函数指针 = 方法
} Dog;

// 唯一的一份函数体,复用给所有 Dog
void dog_bark(Dog *self) {
    printf("%s: wang!\n", self->name);   // 靠 self 区分数据
}

int main(void) {
    Dog a = {"a", dog_bark};
    Dog b = {"b", dog_bark};

    a.bark(&a);   // 输出 a: wang!
    b.bark(&b);   // 输出 b: wang!

    // 关键:两个对象的函数指针指向同一地址
    printf("%d\n", a.bark == b.bark);   // 1,同一个函数体
}

a.barkb.bark 值相同 ------ 证明代码复用了同一函数体 ,区别只在传入的 self(数据)不同。

关键点:self 参数不可省

C 没有 C++ 的隐式 this。函数体要访问"当前对象"的数据,必须显式把对象指针传进去 (惯例命名 self/this)。否则一份共享的函数体无从知道该操作哪个实例的数据。

更省内存的做法:vtable

如果每个对象都在结构体里塞一堆函数指针,指针本身也会被每个实例复制一份,浪费内存。工程上常把方法集中到一张"虚表"里,对象只存一个指向虚表的指针:

c 复制代码
typedef struct Animal Animal;

typedef struct {                       // 虚表:全类共享一份
    void (*speak)(Animal *self);
    void (*eat)(Animal *self);
} AnimalVTable;

struct Animal {
    const AnimalVTable *vtbl;          // 只存一个指针
    char name[32];
};

static const AnimalVTable DOG_VT = { dog_speak, dog_eat };
// 所有 Dog 实例的 vtbl 都指向 &DOG_VT

这就是 C++ 虚函数、以及 Linux 内核(如 file_operationsstruct device)的实现套路 ------ 函数体一份、虚表一份、数据每对象一份,复用最大化。


一句话总结:是的,函数指针只是"地址",指向的函数体被所有对象复用;真正每个对象独立的是结构体里的数据,靠显式 self 参数把数据喂给那份共享的代码。

顺带一提,这套模式在你这个 app 仓库里也有体现 ------ 比如 app业务 的表通过 TABLE_DESC/KEY/FIELD 宏描述,再由统一的 内存表 引擎代码去操作不同表的数据,思路是相通的(用一份引擎代码复用到多张表)。需要的话我可以在仓库里找几个具体例子讲。

相关推荐
天外天-亮2 小时前
HBuilder X 使用 uview-plus 方式
开发语言·javascript·hbuilder x·uview-plus
三品吉他手会点灯2 小时前
嵌入式机器学习 - 学习笔记1.1.1 - 什么是机器学习?
c语言·人工智能·笔记·嵌入式硬件·学习·机器学习
木木子222 小时前
[特殊字符] 音乐播放器——状态驱动的多媒体控制
android·开发语言·华为·php·harmonyos
六个九十度3 小时前
用python脚本访问被网关隔离的嵌入式设备
开发语言·python
酷酷的身影3 小时前
Drivers/LedManager.cs
开发语言·php
小樱花的樱花3 小时前
Linux 线程的创建
linux·c语言·开发语言
xiaoshuaishuai83 小时前
C# AI实现PR处理、单元测试
开发语言·c#·log4j
C++、Java和Python的菜鸟3 小时前
第7章 Java高级技术
java·开发语言
LONGZHIQIN3 小时前
C#基础复习笔记
开发语言·笔记·c#