文章目录
在C语言中没有像C++那样直接的多态机制,但可以通过函数指针和结构体来模拟实现多态的效果,以下是根据C++多态的实现原理,采用C语言语法来实现C++多态:
1、动态多态
定义结构体
#include <stdio.h>
#include <stdlib.h>
// 定义一个基类结构体
typedef struct {
void (*draw)(void*);
} Shape;
这里定义了一个Shape
结构体,其中包含一个函数指针draw
,用于指向不同形状的绘制函数。
定义具体形状的绘制函数
// 绘制圆形的函数
void drawCircle(void* circle) {
printf("Drawing a circle\n");
}
// 绘制矩形的函数
void drawRectangle(void* rectangle) {
printf("Drawing a rectangle\n");
}
创建具体形状的结构体及初始化函数
// 定义圆形结构体
typedef struct {
Shape shape;
// 其他圆形特有的属性
} Circle;
// 定义矩形结构体
typedef struct {
Shape shape;
// 其他矩形特有的属性
} Rectangle;
// 初始化圆形
Circle* createCircle() {
Circle* circle = (Circle*)malloc(sizeof(Circle));
circle->shape.draw = drawCircle;
return circle;
}
// 初始化矩形
Rectangle* createRectangle() {
Rectangle* rectangle = (Rectangle*)malloc(sizeof(Rectangle));
rectangle->shape.draw = drawRectangle;
return rectangle;
}
测试多态效果
int main() {
Shape* shapes[2];
shapes[0] = (Shape*)createCircle();
shapes[1] = (Shape*)createRectangle();
// 遍历并调用draw函数,实现多态效果
for (int i = 0; i < 2; i++) {
shapes[i]->draw(shapes[i]);
}
// 释放内存
free(shapes[0]);
free(shapes[1]);
return 0;
}
在上述代码中,通过函数指针将不同形状的绘制函数与相应的结构体关联起来。在main
函数中,创建了一个Shape
指针数组,分别指向圆形和矩形的结构体实例。通过遍历数组并调用draw
函数,实现了根据不同的对象类型调用不同的绘制函数,模拟了多态的行为。
#include <stdio.h>
#include <stdlib.h>
typedef struct Animal
{
char m_strname[1024];
void (*eat)();
} Animal;
typedef struct Dog
{
Animal m_animal;
} Dog;
typedef struct Cat
{
Animal m_animal;
} Cat;
void dogeat() {
printf("狗吃骨头\n");
}
void cateat() {
printf("猫吃鱼\n");
}
Dog* CreateDog()
{
Dog* p = (Dog*)malloc(sizeof(Dog));
if (p == NULL)
{
fprintf(stderr, "内存分配失败\n");
return NULL;
}
p->m_animal.eat = dogeat;
return p;
}
Cat* CreateCat()
{
Cat* p = (Cat*)malloc(sizeof(Cat));
if (p == NULL)
{
fprintf(stderr, "内存分配失败\n");
return NULL;
}
p->m_animal.eat = cateat;
return p;
}
int main()
{
Cat* cat = CreateCat();
if (cat == NULL)
{
return 1;
}
Animal* m1 = (Animal*)cat;
m1->eat();
// 释放动态分配的内存
free(cat);
return 0;
}
2、静态多态
在C语言中,虽然没有像C++那样原生的静态多态机制,但可以通过一些技巧来模拟类似静态多态的行为,比如利用宏定义和函数指针来实现基于参数类型的不同行为。以下是一个简单示例:
定义函数指针和结构体
#include <stdio.h>
// 定义函数指针类型
typedef void (*Operation)(int, int);
// 定义一个结构体来存储操作函数和操作名称
typedef struct {
const char* name;
Operation op;
} MathOperation;
定义具体的操作函数
// 加法操作函数
void add(int a, int b) {
printf("Addition: %d + %d = %d\n", a, b, a + b);
}
// 减法操作函数
void subtract(int a, int b) {
printf("Subtraction: %d - %d = %d\n", a, b, a - b);
}
定义宏来模拟函数重载
// 定义宏来根据操作类型调用相应的函数
#define DO_OPERATION(operation, a, b) \
do { \
const MathOperation* op = &operation; \
op->op(a, b); \
} while (0)
测试代码
int main() {
// 定义加法和减法操作
MathOperation addOp = {"Add", add};
MathOperation subtractOp = {"Subtract", subtract};
// 调用加法操作
DO_OPERATION(addOp, 5, 3);
// 调用减法操作
DO_OPERATION(subtractOp, 5, 3);
return 0;
}
在上述代码中,通过MathOperation
结构体和函数指针Operation
来存储不同的数学操作函数和操作名称。利用DO_OPERATION
宏根据传入的不同操作结构体来调用相应的函数,在编译时根据传入的参数确定调用哪个函数,类似于静态多态中的函数重载,在一定程度上实现了根据不同参数类型或操作类型执行不同函数的效果。
3、函数指针、指针函数
函数指针和指针函数是C语言中两个不同的概念,它们的区别主要体现在以下几个方面:
概念
- 函数指针:是一个指向函数的指针变量,它存储的是函数的入口地址,通过函数指针可以调用它所指向的函数。
- 指针函数:是一个函数,其返回值是一个指针类型,即函数执行完成后返回一个内存地址。
定义形式
- 函数指针:
返回值类型 (*指针变量名)(参数列表)
。例如,int (*p)(int, int)
,定义了一个名为p
的函数指针,它可以指向返回值为int
型,且有两个int
型参数的函数。 - 指针函数:
返回值类型* 函数名(参数列表)
。例如,int* func(int a, int b)
,定义了一个名为func
的指针函数,它接受两个int
型参数,返回一个int
型指针。
用途
- 函数指针:常用于回调函数、实现函数的动态调用等场景。比如在排序函数中,可以传递一个函数指针来指定不同的比较规则。
- 指针函数:常用于需要返回一个动态分配的内存地址或者指向某个数据结构的指针的情况。比如,从函数中返回一个指向动态分配数组的指针。
示例代码
- 函数指针
#include <stdio.h>
// 定义一个函数
int add(int a, int b) {
return a + b;
}
int main() {
// 定义一个函数指针并指向add函数
int (*p)(int, int) = add;
// 通过函数指针调用函数
int result = p(3, 5);
printf("Result: %d\n", result);
return 0;
}
- 指针函数
#include <stdio.h>
#include <stdlib.h>
// 定义一个指针函数
int* createArray(int size) {
int* arr = (int*)malloc(size * sizeof(int));
for (int i = 0; i < size; i++) {
arr[i] = i;
}
return arr;
}
int main() {
// 调用指针函数
int* ptr = createArray(5);
for (int i = 0; i < 5; i++) {
printf("%d ", ptr[i]);
}
// 释放内存
free(ptr);
return 0;
}