在C语言中,没有直接的 extends 关键字(这个关键字存在于Java、C#等面向对象语言中),C语言不是纯粹的面向对象语言,但它通过结构体(struct)和函数指针提供了一些类似面向对象编程(OOP)的特性,可以用来模拟继承、多态等概念。

(图片来源网络,侵删)
下面我将详细解释如何在C语言中模拟“继承”和“多态”,并提供代码示例。
模拟继承(Inheritance)
在C语言中,可以通过结构体嵌套来模拟继承关系,基本思路是:
- 基类(父类):用一个结构体表示。
- 派生类(子类):用另一个结构体表示,其中包含基类结构体作为其第一个成员(遵循“继承”原则)。
示例:基类 Animal 和派生类 Dog
#include <stdio.h>
#include <string.h>
// 基类(父类)
typedef struct {
char name[50];
int age;
} Animal;
// 派生类(子类)Dog,继承自 Animal
typedef struct {
Animal base; // 包含基类作为第一个成员(模拟继承)
char breed[50];
} Dog;
// 初始化 Animal
void animal_init(Animal* a, const char* name, int age) {
strcpy(a->name, name);
a->age = age;
}
// 初始化 Dog
void dog_init(Dog* d, const char* name, int age, const char* breed) {
animal_init(&d->base, name, age); // 调用基类的初始化函数
strcpy(d->breed, breed);
}
// 打印 Animal 信息
void animal_print(const Animal* a) {
printf("Name: %s, Age: %d\n", a->name, a->age);
}
// 打印 Dog 信息(可以访问基类和派生类的成员)
void dog_print(const Dog* d) {
animal_print(&d->base); // 调用基类的打印函数
printf("Breed: %s\n", d->breed);
}
int main() {
Dog my_dog;
dog_init(&my_dog, "Buddy", 3, "Golden Retriever");
dog_print(&my_dog);
// 也可以直接访问基类成员
printf("Direct access to base: %s\n", my_dog.base.name);
return 0;
}
关键点:
Dog结构体包含Animal作为第一个成员,确保内存布局兼容(可以强制转换为Animal*)。- 派生类可以调用基类的函数(如
animal_init和animal_print)。 - 派生类可以扩展自己的成员(如
breed)。
模拟多态(Polymorphism)
C语言没有虚函数(virtual),但可以通过函数指针和结构体封装来模拟多态,基本思路是:
- 在基类结构体中定义一个函数指针表(类似虚函数表)。
- 派生类可以重写这些函数指针,实现不同的行为。
示例:多态的 Animal 和 Dog
#include <stdio.h>
#include <string.h>
// 基类(父类)
typedef struct {
char name[50];
int age;
void (*speak)(const struct Animal*); // 函数指针(模拟虚函数)
} Animal;
// 派生类(子类)Dog
typedef struct {
Animal base; // 继承 Animal
char breed[50];
} Dog;
// Animal 的 speak 函数(默认行为)
void animal_speak(const Animal* a) {
printf("%s says: Generic animal sound!\n", a->name);
}
// Dog 的 speak 函数(重写)
void dog_speak(const Animal* a) {
const Dog* d = (const Dog*)a; // 强制转换为 Dog 类型
printf("%s (a %s) says: Woof!\n", a->name, d->breed);
}
// 初始化 Animal
void animal_init(Animal* a, const char* name, int age, void (*speak_func)(const Animal*)) {
strcpy(a->name, name);
a->age = age;
a->speak = speak_func; // 设置函数指针(可以是默认的或派生类的)
}
// 初始化 Dog
void dog_init(Dog* d, const char* name, int age, const char* breed) {
animal_init(&d->base, name, age, dog_speak); // 设置 Dog 的 speak 函数
strcpy(d->breed, breed);
}
int main() {
Animal generic_animal;
animal_init(&generic_animal, "Generic Animal", 5, animal_speak);
Dog my_dog;
dog_init(&my_dog, "Buddy", 3, "Golden Retriever");
// 调用 speak 函数(多态行为)
generic_animal.speak(&generic_animal); // 输出: Generic animal sound!
my_dog.base.speak(&my_dog.base); // 输出: Buddy (a Golden Retriever) says: Woof!
return 0;
}
关键点:
- 基类
Animal包含一个函数指针speak,指向不同的实现。 - 派生类
Dog重写speak函数,并通过animal_init设置自己的函数指针。 - 调用时通过基类指针调用函数,实际执行的是派生类的函数(多态)。
其他面向对象特性的模拟
封装(Encapsulation)
- C语言没有
private/public关键字,但可以通过:- 将结构体和函数声明放在头文件(
.h)中,隐藏实现细节(如static函数)。 - *使用
typedef和 `void`** 隐藏内部数据结构。
- 将结构体和函数声明放在头文件(
抽象类(Abstract Class)
- 可以定义一个纯虚函数(函数指针设为
NULL),如果调用则报错。
typedef struct {
// ...
void (*virtual_function)(const struct*); // 设为 NULL 表示纯虚函数
} AbstractClass;
void call_virtual_function(const AbstractClass* obj) {
if (obj->virtual_function == NULL) {
printf("Error: Pure virtual function called!\n");
return;
}
obj->virtual_function(obj);
}
| OOP 特性 | C语言模拟方式 |
|---|---|
| 继承 | 结构体嵌套(派生类包含基类作为第一个成员) |
| 多态 | 函数指针(基类定义虚函数指针,派生类重写) |
| 封装 | 头文件隐藏 + static 函数 |
| 抽象类 | 纯虚函数(函数指针设为 NULL) |
虽然C语言没有原生的 extends 关键字,但通过结构体和函数指针,可以灵活地模拟面向对象编程的核心特性,这在需要高性能或与C代码交互的场景中非常有用(如Linux内核、嵌入式系统等)。

(图片来源网络,侵删)

(图片来源网络,侵删)
