C语言本身不支持面向对象的类语法,但可以通过结构体和函数指针的组合,模拟出类的核心特性,包括属性封装、成员方法、甚至简单的继承和多态效果。这种方式在很多底层框架和嵌入式开发中都有广泛应用。

基础类结构的封装
类的核心包含两部分:成员变量和成员方法。在C语言中,我们可以用struct结构体来存放成员变量,用函数指针来模拟成员方法。首先定义一个简单的类结构,比如模拟一个学生类,包含姓名和年龄两个属性,以及一个打印信息的方法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义学生类结构体
typedef struct Student {
// 成员变量
char name[20];
int age;
// 成员方法:函数指针
void (*print_info)(struct Student* self);
} Student;
// 成员方法的实现
void student_print_info(Student* self) {
printf("姓名:%s,年龄:%dn", self->name, self->age);
}
// 类初始化函数,类似构造函数
Student* student_create(const char* name, int age) {
Student* stu = (Student*)malloc(sizeof(Student));
if (stu == NULL) {
return NULL;
}
strcpy(stu->name, name);
stu->age = age;
// 绑定成员方法到函数指针
stu->print_info = student_print_info;
return stu;
}
// 类销毁函数,类似析构函数
void student_destroy(Student* stu) {
if (stu != NULL) {
free(stu);
}
}
类的使用方式
完成结构体和相关函数的定义后,就可以像使用类一样操作这个结构体实例,通过实例调用绑定的成员方法,访问成员变量。
int main() {
// 创建学生类实例
Student* stu = student_create("张三", 18);
if (stu == NULL) {
return -1;
}
// 访问成员变量
printf("初始年龄:%dn", stu->age);
stu->age = 19;
// 调用成员方法
stu->print_info(stu);
// 销毁实例
student_destroy(stu);
return 0;
}
模拟访问控制
面向对象语言通常有public、private等访问权限控制,C语言中没有原生支持,但可以通过隐藏结构体定义的方式模拟private成员。我们把结构体的完整定义放在.c文件中,在.h文件中只声明结构体类型,外部就无法直接访问结构体的成员变量。
头文件student.h的内容:
#ifndef STUDENT_H #define STUDENT_H // 声明结构体类型,不暴露内部成员 typedef struct Student Student; // 对外暴露的接口 Student* student_create(const char* name, int age); void student_destroy(Student* stu); void student_set_age(Student* stu, int age); int student_get_age(Student* stu); void student_print_info(Student* stu); #endif
源文件student.c的内容:
#include "student.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 结构体的完整定义,仅在当前文件可见
struct Student {
char name[20];
int age;
};
// 实现对外接口
Student* student_create(const char* name, int age) {
Student* stu = (Student*)malloc(sizeof(Student));
if (stu == NULL) {
return NULL;
}
strcpy(stu->name, name);
stu->age = age;
return stu;
}
void student_destroy(Student* stu) {
if (stu != NULL) {
free(stu);
}
}
void student_set_age(Student* stu, int age) {
if (stu != NULL) {
stu->age = age;
}
}
int student_get_age(Student* stu) {
if (stu != NULL) {
return stu->age;
}
return -1;
}
void student_print_info(Student* stu) {
if (stu != NULL) {
printf("姓名:%s,年龄:%dn", stu->name, stu->age);
}
}
这样外部代码只能通过提供的接口操作实例,无法直接修改name和age成员,实现了类似private的访问控制效果。
模拟继承特性
继承可以通过在子结构体开头放置父结构体实例来实现,子结构体可以访问父结构体的成员和方法。比如定义一个大学生类,继承学生类的属性,额外增加专业属性。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 父类:学生
typedef struct Student {
char name[20];
int age;
void (*print_info)(struct Student* self);
} Student;
void student_print_info(Student* self) {
printf("姓名:%s,年龄:%dn", self->name, self->age);
}
Student* student_create(const char* name, int age) {
Student* stu = (Student*)malloc(sizeof(Student));
if (stu == NULL) {
return NULL;
}
strcpy(stu->name, name);
stu->age = age;
stu->print_info = student_print_info;
return stu;
}
// 子类:大学生,开头放置父结构体
typedef struct CollegeStudent {
Student parent; // 继承父类的成员和方法
char major[20]; // 子类新增属性
void (*print_college_info)(struct CollegeStudent* self);
} CollegeStudent;
void college_student_print_info(CollegeStudent* self) {
// 调用父类的方法
self->parent.print_info((Student*)self);
printf("专业:%sn", self->major);
}
CollegeStudent* college_student_create(const char* name, int age, const char* major) {
CollegeStudent* stu = (CollegeStudent*)malloc(sizeof(CollegeStudent));
if (stu == NULL) {
return NULL;
}
strcpy(stu->parent.name, name);
stu->parent.age = age;
stu->parent.print_info = student_print_info;
strcpy(stu->major, major);
stu->print_college_info = college_student_print_info;
return stu;
}
int main() {
CollegeStudent* stu = college_student_create("李四", 20, "计算机科学");
// 访问父类成员
printf("年龄:%dn", stu->parent.age);
// 调用子类方法
stu->print_college_info(stu);
free(stu);
return 0;
}
注意事项
- 函数指针绑定需要在初始化时完成,否则调用时会出现空指针错误
- 模拟多态时需要注意结构体指针的类型转换,避免内存访问越界
- 手动管理内存,创建实例后一定要记得调用销毁函数释放内存,避免内存泄漏
- 这种实现方式只是模拟类的特性,和原生面向对象的类还是有差异,不要过度设计复杂的继承关系