当前位置: 首页 > news >正文

C语言面向对象编程:模拟实现封装、继承、多态

一、面向对象基本概念

面向对象编程基于三个核心概念:封装、继承和多态。

1. 封装

将数据和操作这些数据的方法封装在一起,形成一个独立的单元(类)。这种机制隐藏了内部实现细节,只暴露必要的接口。

2. 继承

允许基于已存在的类(父类)定义新类(子类),子类可以复用父类的属性和方法,并可以添加新的属性和方法。

3. 多态

允许不同类的对象对同一消息作出响应,实现方法的动态绑定,提高了代码的灵活性和可扩展性。

二、C语言模拟封装实现

封装是面向对象编程的基础。在C语言中,我们可以使用结构体来封装数据,并通过函数指针来封装方法。

0. 头文件枚举值定义

typedef enum {HAL_OK = 0x00,HAL_ERROR = 0x01,
} HAL_StatusTypeDef;

1. String 类的实现

1. 结构体定义

// 定义String结构体,模拟类  
typedef struct String {/* 成员函数 */// HAL_StatusTypeDef(*_init_string)(String* self, const char* str); // 构造函数(无法在对象初始化前通过对象调用)HAL_StatusTypeDef(*_destroy_string)(struct String* self); // 析构函数HAL_StatusTypeDef(*_PrintString)(const struct String* const self); // 打印String/* 成员变量 */char* _str; // 字符串size_t _size;  // 长度size_t _capacity;  // 容量
} String;

2. 构造函数

/* String对象构造函数 */
HAL_StatusTypeDef init_string(String* self, const char* str) 
{// 初始化成员变量self->_size = strlen(str);self->_capacity = self->_size;self->_str = (char*)malloc(sizeof(char) * self->_size + 1);memcpy(self->_str, str, self->_size + 1);// 注入成员函数// self->_init_string = init_string;self->_destroy_string = destroy_string;self->_PrintString = PrintString;return HAL_OK;
}

说明:

  • 构造函数负责初始化对象和注入方法

  • 需要手动调用,模拟构造函数行为

3. 析构函数

/* String对象析构函数 */
HAL_StatusTypeDef destroy_string(String* self) 
{free(self->_str);self->_str = NULL;return HAL_OK;
}

说明:

  • 显式释放分配的内存

  • 需要手动调用,模拟析构函数行为

4. 功能函数

/* String对象打印函数 */
HAL_StatusTypeDef PrintString(const String* const self) 
{printf("%s\n", self->_str);return HAL_OK;
}

2. Person 类的实现

1. 结构体定义

// 定义Person结构体,模拟类  
typedef struct Person {/* 成员函数 */// HAL_StatusTypeDef(*_init_person)(Person* self, char* name, int age); // 构造函数(无法在对象初始化前通过对象调用)HAL_StatusTypeDef(*_destroy_person)(struct Person* self); // 析构函数HAL_StatusTypeDef(*_speak)(const struct Person* const self); // 指向speak方法的指针/* 成员变量 */char* _name; // 姓名int _age;    // 年龄
} Person;

2. 构造函数

/* Person对象构造函数 */
HAL_StatusTypeDef init_person(Person* self, char* name, int age) {// 初始化成员变量self->_name = name;self->_age = age;self->_speak = speak_func;  // 函数名就是函数的地址,与&speak_func等价// self->_init_person = init_person;    // 将构造函数的地址赋值给_init_personself->_destroy_person = destroy_person; // 将析构函数的地址赋值给_destroy_personreturn HAL_OK;
}

3. 析构函数

/* Person对象析构函数 */
HAL_StatusTypeDef destroy_person(Person* self) {self->_name = NULL;self->_age = 0;return HAL_OK;
}

4. 功能函数

// 定义speak方法  
HAL_StatusTypeDef speak_func(const Person* const self) {printf("Hello, I am %s, %d years old.\n", self->_name, self->_age);return HAL_OK;
}

3. main测试代码

int main() {/* 封装类 */String s1;  // 创建String实例init_string(&s1, "Hello world!");   // 构造函数s1._PrintString(&s1);       // 调用功能函数s1._destroy_string(&s1);    // 析构函数Person p1; // 创建Person实例init_person(&p1, "Alice", 30);  // 构造函数p1._speak(&p1);             // 调用功能函数p1._destroy_person(&p1);    // 析构函数return 0;
}

说明:

  • 演示了对象的创建、使用和销毁过程

  • 展示了如何调用对象的方法

三、C语言模拟继承实现

1. 子类 Student 结构体定义

// 定义Student结构体,模拟类  
typedef struct Student {/* 继承父类 */Person _Person; // 继承Person类// 放在子类结构体的第一个成员,这样可以通过(Person*)self获取父类的指针,传入父类的构造函数和析构函数/* 成员函数 */HAL_StatusTypeDef(*_print_score)(const struct Student* const self); // 打印分数HAL_StatusTypeDef(*_destroy_Student)(struct Student* self); // 析构函数/* 成员变量 */int _math_score; // 数学分数int _English_score; // 英语分数int _Chinese_score; // 语文分数
} Student;

说明:

  • 通过结构体嵌套实现继承

  • 父类作为子类的第一个成员,便于类型转换

2. Student类构造函数

/* 构造函数 */
HAL_StatusTypeDef init_Student(Student* const self, const char* name, int age, int math_score, int English_score, int Chinese_score)
{// 初始化父类结构体init_person((Person*)self, name, age);// 初始化成员变量self->_Chinese_score = Chinese_score;self->_English_score = English_score;self->_math_score = math_score;self->_print_score = print_score;self->_destroy_Student = destroy_Student;return HAL_OK;
}

说明:

  • 先初始化父类部分,再初始化子类特有部分

  • 通过类型转换将Student转换为Person

3. Student类析构函数

HAL_StatusTypeDef destroy_Student(Student* self) // 析构函数
{// 先析构子类self->_Chinese_score = 0;self->_English_score = 0;self->_math_score = 0;// 再析构父类self->_Person._destroy_person((Person*)self);return HAL_OK;
}

说明:

  • 析构顺序:先子类后父类

  • 模拟了继承体系中的析构过程

4. 功能函数实现

HAL_StatusTypeDef print_score(const Student* const self) // 打印分数
{printf("Math: %d\n", self->_math_score);printf("English: %d\n", self->_English_score);printf("Chinese: %d\n", self->_Chinese_score);return HAL_OK;
}

5. main测试代码

int main() {/* 继承 */Student stu2; // 创建Student实例init_Student(&stu2, "Bob", 20, 90, 85, 95); // 构造函数stu2._print_score(&stu2);   // 打印成绩stu2._Person._speak(&stu2); // 说话函数,存在隐式类型转换,将子类结构体地址转化成父类结构体地址stu2._destroy_Student(&stu2);   // 析构函数// 查看是否完成析构printf("stu2 math_score:%d\n", stu2._math_score);printf("stu2 name:%p\n", stu2._Person._name);return 0;
}

三、C语言模拟多态实现

1. 多态实现完整代码

#include <stdio.h>// 1. 定义“基类”Animal:包含通用属性(name)和“虚函数指针”(speak)
// 核心:用函数指针封装“共有的方法接口”,不同子类通过赋值不同函数实现差异化
typedef struct {const char* name;               void (*speak)(const void* self); // 函数指针:指向“发声”方法(self指向具体对象)
} Animal;// 2. 定义“子类”Dog:通过嵌套基类Animal实现“继承”
// 逻辑:子类结构体包含基类结构体作为第一个成员,模拟“子类继承基类的属性和方法”
typedef struct {Animal base;  const char* breed; 
} Dog;// 3. 实现Dog的“发声”方法(对应基类的speak接口)
// 参数self:通用指针,指向具体的Dog对象(需强制转换)
void dog_speak(const void* self) {// 将通用指针转为Dog*,才能访问其嵌套的base成员const Dog* dog = (const Dog*)self;printf("[Dog] %s (breed: %s) barks: Wang Wang!\n", dog->base.name, dog->breed);
}// 4. 定义“子类”Cat:同样通过嵌套Animal实现“继承”
typedef struct {Animal base;    const char* color;
} Cat;// 5. 实现Cat的“发声”方法(对应基类的speak接口)
void cat_speak(const void* self) {const Cat* cat = (const Cat*)self;printf("[Cat] %s (color: %s) meows: Miao Miao!\n", cat->base.name, cat->color);
}// 6. 封装“创建Dog对象”的函数(相当于构造函数)
// 功能:初始化Dog的属性,并将其base的speak指向Dog的实现
Dog* create_dog(const char* name, const char* breed) {// 简化示例:用静态变量避免堆内存管理(实际开发可改用malloc)static Dog dog;//Dog* dog = malloc(szieof(Dog)); 这时引用dog的成员要使用 ->dog.base.name = name;      dog.base.speak = dog_speak; dog.breed = breed;          return &dog;
}// 7. 封装“创建Cat对象”的函数(构造函数)
Cat* create_cat(const char* name, const char* color) {static Cat cat;//Cat* cat= malloc(szieof(Cat));cat.base.name = name;       cat.base.speak = cat_speak; cat.color = color;          return &cat;
}// 8. 通用接口函数:接收“基类指针”(Animal*),调用speak方法
// 核心:通过基类指针调用函数指针,实现“多态”——同一接口,不同实现
void animal_speak(const Animal* animal) {if (animal && animal->speak) { // 调用函数指针,传入具体对象(animal指向的实际是Dog/Cat的base成员)animal->speak(animal); }
}int main() {Dog* dog = create_dog("Buddy", "Golden Retriever");Cat* cat = create_cat("Luna", "White");// 多态体现:调用同一接口animal_speak,根据实际对象类型执行不同实现animal_speak(&dog->base); // 传入Dog的base成员(Animal类型),执行dog_speakanimal_speak(&cat->base); // 传入Cat的base成员(Animal类型),执行cat_speakreturn 0;
}

核心原理解析(C 语言模拟多态的 3 个关键)

C 语言没有类、继承、虚函数等面向对象特性,上述代码通过3 个核心技术模拟多态,本质是 “接口统一,实现分离”:

  1. 用 “结构体嵌套” 模拟 “继承关系”

  • 面向对象中,子类继承基类的属性和方法;C 语言中,通过 “子类结构体嵌套基类结构体” 实现类似效果。

    • 例如Dog结构体第一个成员是Animal base,这意味着:

      • Dog对象的内存布局中,开头部分与Animal完全一致(可直接将&dog->base视为Animal*指针)。

      • Dog可以 “继承”Animal的属性(name)和方法接口(speak函数指针)。

    • 子类可额外添加特有属性(如DogbreedCatcolor),实现 “扩展”。

  1. 用 “函数指针” 模拟 “虚函数”(多态的核心)

  • 面向对象的多态依赖 “虚函数”(基类声明虚函数,子类重写);C 语言中,用基类结构体中的函数指针模拟 “虚函数接口”。

    • 基类Animal中的void (*speak)(const void* self)是 “通用方法接口”,所有子类(Dog、Cat)都需实现对应的具体函数(dog_speakcat_speak)。

    • 创建子类对象时(如create_dog函数),将基类的speak函数指针绑定到子类的具体实现(dog->base.speak = dog_speak),这一步相当于 “子类重写虚函数”。

  1. 用 “基类指针” 实现 “动态绑定”

  • 多态的关键是 “运行时根据实际对象类型,调用对应实现”(动态绑定);C 语言中,通过 “基类指针(Animal)指向子类对象的基类成员*” 实现。

    • main函数中,animal_speak(&dog->base)animal_speak(&cat->base)调用的是同一个接口animal_speak,但传入的Animal*指针实际指向:

      • &dog->base:指向Dog对象中的Animal成员,其speak绑定的是dog_speak

      • &cat->base:指向Cat对象中的Animal成员,其speak绑定的是cat_speak

    • 运行时,animal->speak(animal)会根据speak指针实际指向的函数(dog_speakcat_speak)执行,从而实现 “同一接口,不同行为” 的多态效果。

main()|| 创建对象+--> create_dog() --> Dog对象.base.speak = dog_speak|+--> create_cat() --> Cat对象.base.speak = cat_speak|| 多态调用+--> animal_speak(&dog->base)|     ||     +--> animal->speak(animal) --> 实际调用 dog_speak(dog)|+--> animal_speak(&cat->base)|+--> animal->speak(animal) --> 实际调用 cat_speak(cat)

运行结果

[Dog] Buddy (breed: Golden Retriever) barks: Wang Wang!
[Cat] Luna (color: White) meows: Miao Miao!

核心总结

C 语言模拟多态的本质是 “用结构化思维手动实现面向对象的核心逻辑”,对比面向对象语言(如 C++):

面向对象概念(C++)C语言模拟方式
基类(父类)/派生类(子类)

结构体嵌套(子类包含基类结构体)

虚函数

基类结构体中的函数指针

重写(覆盖)(Override)

子类对象给基类函数指针赋值

动态绑定

基类指针指向子类的基类成员

这种方式的局限性:需要手动管理 “继承”(结构体嵌套)和 “虚函数绑定”(函数指针赋值),没有编译器自动支持;但通过统一接口封装不同实现,能让代码更灵活、可扩展。


文章转载自:

http://I4avQWDh.xqgtd.cn
http://Wo61rx8w.xqgtd.cn
http://ipp8ghkp.xqgtd.cn
http://6cCYMswV.xqgtd.cn
http://AEms7icz.xqgtd.cn
http://sXm1C590.xqgtd.cn
http://0q8YRm7Y.xqgtd.cn
http://TGep1WkE.xqgtd.cn
http://owwxB5FG.xqgtd.cn
http://dGi6276d.xqgtd.cn
http://bnRVWD4Y.xqgtd.cn
http://DHJZBzyr.xqgtd.cn
http://WaX7xWWZ.xqgtd.cn
http://ZUcpLdYm.xqgtd.cn
http://DJQEXgMr.xqgtd.cn
http://VYtSHp33.xqgtd.cn
http://YeaiD263.xqgtd.cn
http://k9s7CdTY.xqgtd.cn
http://owdY4acc.xqgtd.cn
http://Cpm0kHY4.xqgtd.cn
http://3bxdCUjK.xqgtd.cn
http://tgkqWA2h.xqgtd.cn
http://TBdTnKdr.xqgtd.cn
http://Zd6Uuzw3.xqgtd.cn
http://nY3SdTKj.xqgtd.cn
http://8AcozSXd.xqgtd.cn
http://ajrNRSuF.xqgtd.cn
http://V1eGPX5V.xqgtd.cn
http://SMcHzr5q.xqgtd.cn
http://XqBOfeID.xqgtd.cn
http://www.dtcms.com/a/375669.html

相关文章:

  • 设计 模式
  • 【Scientific Data 】紫茎泽兰的染色体水平基因组组装
  • MVCC-多版本并发控制
  • 【MybatisPlus】SpringBoot3整合MybatisPlus
  • 如何在FastAPI中玩转“时光倒流”的数据库事务回滚测试?
  • MySQL数据库面试题整理
  • PostgreSQL 大对象管理指南:pg_largeobject 从原理到实践
  • 传统项目管理的局限性有哪些
  • 内核函数:copy_process
  • 《UE5_C++多人TPS完整教程》学习笔记50 ——《P51 多人游戏中的俯仰角(Pitch in Multiplayer)》
  • RL【5】:Monte Carlo Learning
  • 深度解析HTTPS:从加密原理到SSL/TLS的演进之路
  • minio 文件批量下载
  • 【算法专题训练】19、哈希表
  • AJAX入门-URL、参数查询、案例查询
  • 安装ultralytics
  • Eino ChatModel 组件指南摘要
  • 腾讯codebuddy-cli重磅上线-国内首家支持全形态AI编程工具!
  • 基于PCL(Point Cloud Library)的点云高效处理方法
  • UVa1302/LA2417 Gnome Tetravex
  • STC Link1D电脑端口无法识别之升级固件
  • 【C++】LLVM-mingw + VSCode:Windows 开发攻略
  • SRM系统有哪些核心功能?企业该如何科学选型?
  • LINUX99 centos8:网络 yum配置;shell:while [ $i -ne 5 ];do let i++ done
  • 【陇剑杯2025】密码复现(部分)
  • 漫谈《数字图像处理》之图像自适应阈值处理
  • Melon: 基于marker基因的三代宏基因组分类和定量软件
  • 水题记录1.7
  • JVM 执行引擎详解!
  • lua中 string.match返回值