项目链接 https://github.com/viys/OOP-By-Viys.git
文件源码贴在文末
虽然 C 是过程式语言,但我们可以通过 struct
和函数指针模拟出“类、对象、方法”等机制,实现如下特性:
本项目演示了如何在 C 中构造一个支持 OOP 的框架。
oopc/
├─ build
│ └─ my_config.h // 配置项(通过 Kconfig 生成)
└─ project
├─ animal
│ ├─ animal.c // 类实现:Animal、Cat、Dog
│ └─ animal.h // 类接口声明
└─ app
└─ main.c // 程序入口,创建和使用对象
数据私有,通过接口访问
typedef struct {
ANIMAL_CLASS_IMPLEMENTS api;
Animal_Attr attr;
} ANIMAL_CLASS;
外部代码通过 get_name()
访问 attr.name
,而非直接操作:
int animal_get_name(void* t, char* name);
在 main.c
中使用方式:
anmial_cat->get_name(anmial_cat, name);
子类构造函数基于父类对象构造,只重写行为
构造函数示例(dog):
DOG_CLASS* DOG_CLASS_CTOR(ANIMAL_CLASS_IMPLEMENTS* t);
重写 speak
行为:
this->api.speak = dog_speak;
形成“继承自 Animal,仅重写发声”的类结构。
相同接口,不同实现
统一接口:
static int animal_sound(void* t) {
ANIMAL_CLASS_IMPLEMENTS* this = (ANIMAL_CLASS_IMPLEMENTS*)t;
this->speak(this);
return 0;
}
无论传入 cat
还是 dog
,都能调用正确的 speak
方法。
先定义通用接口,各类实现
typedef struct {
int (*init)(void* t, Animal_Attr attr);
int (*get_name)(void* t, char* name);
int (*speak)(void* t);
} ANIMAL_CLASS_IMPLEMENTS;
所有类都必须实现该接口,这构成了最基本的行为契约。
本项目使用 CMake 构建系统,并支持通过 menuconfig
进行配置。
mkdir build
cd build
cmake -G "MinGW Makefiles" ..
cmake ..
请确保已安装 CMake、GCC(或 MinGW)、以及支持
menuconfig
的工具(如 kconfig-frontends)。
kconfig
使用教程详见 https://github.com/viys/kconfig.git,若不想配置则删除#include "my_config.h"
并对CONFIG_ANIMAL_NAME_1
和CONFIG_ANIMAL_NAME_2
作出定义。也可在build
目录下手动创建如下的my_config.h
文件。
make menuconfig
该步骤用于生成配置文件 my_config.h
,例如设置:
#define CONFIG_ANIMAL_NAME_1 "cat"
#define CONFIG_ANIMAL_NAME_2 "dog"
make
oopc.exe
./oopc
>
animal name is cat
animal name is dog
animal cat say: Meow!
animal dog say: Woof!
animal cat say: Meow!
animal dog say: Woof!
<
含义解析:
animal name is ...
:测试封装(通过接口获取名称)say:
:继承后重写 speak
animal_sound
:验证多态接口调用行为特性 | 在代码中的体现 |
---|---|
封装 | get_name() 方法隐藏结构细节 |
继承 | Dog/Cat 构造函数使用 Animal 对象并重写部分方法 |
多态 | animal_sound() 使用统一接口,实际调用因对象而异 |
抽象 | ANIMAL_CLASS_IMPLEMENTS 为统一接口,各类实现其行为 |
✅ 本项目演示了如何用纯 C 模拟 C++/Java 中的类继承结构,是构建模块化、可扩展嵌入式系统的有效实践方式。
my_config.h
#define CONFIG_ANIMAL_NAME_1 "cat"
#define CONFIG_ANIMAL_NAME_2 "dog"
main.c
#include
#include
#include "my_config.h"
#include "animal.h"
ANIMAL_CLASS_IMPLEMENTS* anmial_cat = NULL;
ANIMAL_CLASS_IMPLEMENTS* anmial_dog = NULL;
static int animal_sound(void* t) {
ANIMAL_CLASS_IMPLEMENTS* this = (ANIMAL_CLASS_IMPLEMENTS*)t;
this->speak(this);
return 0;
}
int main()
{
printf(">\r\n");
char name[10] = {0};
Animal_Attr Cat_Attr = {
.name = CONFIG_ANIMAL_NAME_1,
};
Animal_Attr Dog_Attr = {
.name = CONFIG_ANIMAL_NAME_2,
};
// 抽象
anmial_cat = (ANIMAL_CLASS_IMPLEMENTS*)ANIMAL_CLASS_CTOR();
anmial_cat->init(anmial_cat, Cat_Attr);
anmial_dog = (ANIMAL_CLASS_IMPLEMENTS*)ANIMAL_CLASS_CTOR();
anmial_dog->init(anmial_dog, Dog_Attr);
// 封装
memset(name, 0x00, sizeof(name));
anmial_cat->get_name(anmial_cat, name);
printf("animal name is %s\r\n", name);
memset(name, 0x00, sizeof(name));
anmial_dog->get_name(anmial_dog, name);
printf("animal name is %s\r\n", name);
ANIMAL_CLASS_IMPLEMENTS* dog = NULL;
ANIMAL_CLASS_IMPLEMENTS* cat = NULL;
// 继承
cat = (ANIMAL_CLASS_IMPLEMENTS*)CAT_CLASS_CTOR(anmial_cat);
dog = (ANIMAL_CLASS_IMPLEMENTS*)DOG_CLASS_CTOR(anmial_dog);
cat->speak(cat);
dog->speak(dog);
// 多态
animal_sound(cat);
animal_sound(dog);
printf("<\r\n");
return 0;
}
animal.c
#pragma once
typedef struct {
char name[10];
char sound[10];
} Animal_Attr;
typedef struct {
int (*init)(void* t, Animal_Attr attr);
int (*get_name)(void* t, char* name);
int (*speak)(void* t);
} ANIMAL_CLASS_IMPLEMENTS;
typedef struct {
ANIMAL_CLASS_IMPLEMENTS api;
Animal_Attr attr;
} ANIMAL_CLASS;
typedef struct {
char name[10];
} Dog_Attr;
typedef struct {
ANIMAL_CLASS_IMPLEMENTS api;
Dog_Attr attr;
} DOG_CLASS;
typedef struct {
char name[10];
} Cat_Attr;
typedef struct {
ANIMAL_CLASS_IMPLEMENTS api;
Cat_Attr attr;
} CAT_CLASS;
ANIMAL_CLASS* ANIMAL_CLASS_CTOR(void);
void ANIMAL_CLASS_DTOR(ANIMAL_CLASS* t);
DOG_CLASS* DOG_CLASS_CTOR(ANIMAL_CLASS_IMPLEMENTS* t);
void DOG_CLASS_DTOR(DOG_CLASS* t);
CAT_CLASS* CAT_CLASS_CTOR(ANIMAL_CLASS_IMPLEMENTS* t);
void CAT_CLASS_DTOR(CAT_CLASS* t);
animal.h
#include
#include
#include
#include "animal.h"
static int animal_init(void* t, Animal_Attr attr) {
ANIMAL_CLASS* this = (ANIMAL_CLASS*)t;
memcpy(&this->attr, &attr, sizeof(Animal_Attr));
return 0;
}
static int animal_get_name(void* t, char* name) {
ANIMAL_CLASS* this = (ANIMAL_CLASS*)t;
memcpy(name, this->attr.name, strlen(this->attr.name) + 1);
return 0;
}
static int animal_speak(void* t) {
ANIMAL_CLASS* this = (ANIMAL_CLASS*)t;
printf("animal %s say: %s!\r\n", this->attr.name, this->attr.sound);
return 0;
}
ANIMAL_CLASS* ANIMAL_CLASS_CTOR(void) {
ANIMAL_CLASS* this = (ANIMAL_CLASS*)malloc(sizeof(ANIMAL_CLASS));
this->api.init = animal_init;
this->api.get_name = animal_get_name;
this->api.speak = animal_speak;
return this;
}
void ANIMAL_CLASS_DTOR(ANIMAL_CLASS* t) {
free(t);
}
static int dog_speak(void* t) {
DOG_CLASS* this = (DOG_CLASS*)t;
printf("animal %s say: Woof!\r\n", this->attr.name);
return 0;
}
DOG_CLASS* DOG_CLASS_CTOR(ANIMAL_CLASS_IMPLEMENTS* t) {
DOG_CLASS* this = (DOG_CLASS*)malloc(sizeof(DOG_CLASS));
t->get_name(t, this->attr.name);
// 此处没有实现 init get_name 的接口
this->api.speak = dog_speak;
return this;
}
void DOG_CLASS_DTOR(DOG_CLASS* t) {
free(t);
}
static int cat_speak(void* t) {
CAT_CLASS* this = (CAT_CLASS*)t;
printf("animal %s say: Meow!\r\n", this->attr.name);
return 0;
}
CAT_CLASS* CAT_CLASS_CTOR(ANIMAL_CLASS_IMPLEMENTS* t) {
CAT_CLASS* this = (CAT_CLASS*)malloc(sizeof(CAT_CLASS));
t->get_name(t, this->attr.name);
// 此处没有实现 init get_name 的接口
this->api.speak = cat_speak;
return this;
}
void CAT_CLASS_DTOR(CAT_CLASS* t) {
free(t);
}