多态
核心技巧:虚函数表(vtable)—— 基类里放一个指向函数指针表的指针,不同子类填充不同的实现,调用时通过 vtable 间接跳转。
虚函数表 + 基类定义
// 虚函数表类型
typedef struct VTable VTable;
struct VTable {
double (*area)(void* self);
void (*print)(void* self);
};
// 基类
typedef struct {
const char* name;
const VTable* vtable; // 指向子类各自的虚函数表
} Shape;
多态调用入口(统一接口)
double Shape_area(void* self) {
Shape* s = (Shape*)self;
return s->vtable->area(self); // 通过 vtable 跳转到子类实现
}
void Shape_print(void* self) {
Shape* s = (Shape*)self;
s->vtable->print(self); // 通过 vtable 跳转到子类实现
}
子类 Circle
typedef struct {
Shape base;
double radius;
} Circle;
static double Circle_area(void* self) {
Circle* c = (Circle*)self;
return M_PI * c->radius * c->radius;
}
static void Circle_print(void* self) {
Circle* c = (Circle*)self;
printf("Circle{radius=%.1f, area=%.1f}", c->radius, Circle_area(self));
}
// Circle 类的虚函数表(静态全局,所有实例共享)
static const VTable CIRCLE_VTABLE = {
.area = Circle_area,
.print = Circle_print,
};
void Circle_init(Circle* c, const char* name, double radius) {
c->base.name = name;
c->base.vtable = &CIRCLE_VTABLE; // 绑定自己的 vtable
c->radius = radius;
}
子类 Rectangle
typedef struct {
Shape base;
double w, h;
} Rectangle;
static double Rect_area(void* self) {
Rectangle* r = (Rectangle*)self;
return r->w * r->h;
}
static void Rect_print(void* self) {
Rectangle* r = (Rectangle*)self;
printf("Rectangle{%.1f x %.1f, area=%.1f}", r->w, r->h, Rect_area(self));
}
static const VTable RECT_VTABLE = {
.area = Rect_area,
.print = Rect_print,
};
void Rectangle_init(Rectangle* r, const char* name, double w, double h) {
r->base.name = name;
r->base.vtable = &RECT_VTABLE;
r->w = w;
r->h = h;
}
子类 Triangle
typedef struct {
Shape base;
double a, b, c;
} Triangle;
static double Tri_area(void* self) {
Triangle* t = (Triangle*)self;
double s = (t->a + t->b + t->c) / 2;
return sqrt(s * (s - t->a) * (s - t->b) * (s - t->c));
}
static void Tri_print(void* self) {
Triangle* t = (Triangle*)self;
printf("Triangle{sides=(%.1f,%.1f,%.1f), area=%.1f}",
t->a, t->b, t->c, Tri_area(self));
}
static const VTable TRI_VTABLE = {
.area = Tri_area,
.print = Tri_print,
};
void Triangle_init(Triangle* t, const char* name, double a, double b, double c) {
t->base.name = name;
t->base.vtable = &TRI_VTABLE;
t->a = a; t->b = b; t->c = c;
}
多态使用
void print_shape_info(void* self) {
Shape_print(self);
printf(" | area = %.1f\n", Shape_area(self));
}
int main(void) {
Circle c;
Rectangle r;
Triangle t;
Circle_init(&c, "c1", 5.0);
Rectangle_init(&r, "r1", 4.0, 3.0);
Triangle_init(&t, "t1", 3.0, 4.0, 5.0);
// 通过 void* 数组统一管理,循环调用
void* shapes[] = { &c, &r, &t };
for (int i = 0; i < 3; i++) {
print_shape_info(shapes[i]); // 各自输出不同的 area
}
return 0;
}
运行结果
=== 多态:同一个函数,不同行为 ===
Circle{radius=5.0, area=78.5} | area = 78.5
Rectangle{4.0 x 3.0, area=12.0} | area = 12.0
Triangle{sides=(3.0,4.0,5.0), area=6.0} | area = 6.0