多态

核心技巧:虚函数表(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