用 C 语言实现面向对象编程(OOP)教程

用 C 语言实现面向对象编程(OOP)教程

——以“动物说话系统”为例

项目链接 https://github.com/viys/OOP-By-Viys.git
文件源码贴在文末


目录

  1. 面向对象简介
  2. 项目结构总览
  3. 四大特性详解
    • 封装(Encapsulation)
    • 继承(Inheritance)
    • 多态(Polymorphism)
    • 抽象(Abstraction)
  4. 编译与运行
  5. 运行结果与解释
  6. 总结

面向对象简介

虽然 C 是过程式语言,但我们可以通过 struct 和函数指针模拟出“类、对象、方法”等机制,实现如下特性:

  • 封装:隐藏内部数据,通过接口访问
  • 继承:子类复用父类属性和方法
  • 多态:相同接口,不同实现
  • 抽象:定义通用接口,屏蔽细节差异

本项目演示了如何在 C 中构造一个支持 OOP 的框架。


项目结构总览

oopc/
├─ build
│  └─ my_config.h	// 配置项(通过 Kconfig 生成)
└─ project
   ├─ animal
   │  ├─ animal.c	// 类实现:Animal、Cat、Dog
   │  └─ animal.h	// 类接口声明
   └─ app
      └─ main.c		// 程序入口,创建和使用对象

四大特性详解

封装(Encapsulation)

数据私有,通过接口访问

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);

继承(Inheritance)

子类构造函数基于父类对象构造,只重写行为

构造函数示例(dog):

DOG_CLASS* DOG_CLASS_CTOR(ANIMAL_CLASS_IMPLEMENTS* t);

重写 speak 行为:

this->api.speak = dog_speak;

形成“继承自 Animal,仅重写发声”的类结构。


多态(Polymorphism)

相同接口,不同实现

统一接口:

static int animal_sound(void* t) {
    ANIMAL_CLASS_IMPLEMENTS* this = (ANIMAL_CLASS_IMPLEMENTS*)t;
    this->speak(this);
    return 0;
}

无论传入 cat 还是 dog,都能调用正确的 speak 方法。


抽象(Abstraction)

先定义通用接口,各类实现

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 进行配置。

步骤 1:创建构建目录

mkdir build
cd build

步骤 2:生成构建系统

Windows(使用 MinGW):
cmake -G "MinGW Makefiles" ..
Linux:
cmake ..

请确保已安装 CMake、GCC(或 MinGW)、以及支持 menuconfig 的工具(如 kconfig-frontends)。


步骤 3:菜单配置(可选)

kconfig 使用教程详见 https://github.com/viys/kconfig.git,若不想配置则删除 #include "my_config.h" 并对 CONFIG_ANIMAL_NAME_1CONFIG_ANIMAL_NAME_2 作出定义。也可在 build 目录下手动创建如下的 my_config.h 文件。

make menuconfig

该步骤用于生成配置文件 my_config.h,例如设置:

#define CONFIG_ANIMAL_NAME_1 "cat"
#define CONFIG_ANIMAL_NAME_2 "dog"

步骤 4:编译项目

make

步骤 5:运行程序

Windows:
oopc.exe
Linux / macOS:
./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);
}

你可能感兴趣的:(c语言,开发语言)