C 無原生 OOP 支援,但可用結構體 + 函數指標模擬:
#include <stdio.h>
#include <stdlib.h>
/* 基類 Shape */
typedef struct Shape {
int edges;
int (*getEdges)(struct Shape*);
double (*getArea)(struct Shape*);
} Shape;
Shape *Shape_new() {
Shape *s = malloc(sizeof(Shape));
s->edges = 0;
s->getEdges = Shape_getEdges;
s->getArea = Shape_getArea;
return s;
}
int Shape_getEdges(Shape *s) { return s->edges; }
double Shape_getArea(Shape *s) { return 0; }
/* 子類 Triangle */
typedef struct Triangle {
Shape super; // 必須為第一成員
double base, height;
} Triangle;
Triangle *Triangle_new(double b, double h) {
Triangle *t = malloc(sizeof(Triangle));
t->super = *Shape_new(); // 繼承基類方法
t->super.edges = 3;
t->base = b; t->height = h;
t->super.getEdges = Triangle_getEdges; // 覆寫
t->super.getArea = Triangle_getArea;
return t;
}
int Triangle_getEdges(Shape *s) { return ((Triangle*)s)->super.edges; }
double Triangle_getArea(Shape *s) {
Triangle *t = (Triangle*)s;
return t->base * t->height / 2;
}
/* 子類 Rectangle */
typedef struct Rectangle {
Shape super;
double width, height;
} Rectangle;
Rectangle *Rectangle_new(double w, double h) {
Rectangle *r = malloc(sizeof(Rectangle));
r->super = *Shape_new();
r->super.edges = 4;
r->width = w; r->height = h;
r->super.getEdges = Rectangle_getEdges;
r->super.getArea = Rectangle_getArea;
return r;
}
int Rectangle_getEdges(Shape *s) { return ((Rectangle*)s)->super.edges; }
double Rectangle_getArea(Shape *s) {
Rectangle *r = (Rectangle*)s;
return r->width * r->height;
}
/* 多態演示 */
int main() {
Shape *shapes[3];
shapes[0] = (Shape*)Triangle_new(3, 4);
shapes[1] = (Shape*)Rectangle_new(5, 6);
shapes[2] = Shape_new();
for (int i=0; i<3; i++) {
printf("Edges: %d, Area: %.1f\n",
shapes[i]->getEdges(shapes[i]),
shapes[i]->getArea(shapes[i]));
}
// 輸出:
// Edges: 3, Area: 6.0
// Edges: 4, Area: 30.0
// Edges: 0, Area: 0.0
return 0;
}
Shape* 可安全轉換為 Triangle*。Triangle_new 先呼叫 Shape_new 初始化基類部分,再覆寫虛函數指標。Shape_delete 遞歸釋放,C++ 編譯器自動處理此點。typedef struct Shape_vtable {
int (*getEdges)(Shape*);
double (*getArea)(Shape*);
} Shape_vtable;
static Shape_vtable shape_vtable = {Shape_getEdges, Shape_getArea};
typedef struct Shape {
Shape_vtable *vptr;
int edges;
} Shape;
// 子類建構時設定 vptr 指向各自的 static vtable
// 實例大小減少 (不再存每個方法指標),間接呼叫: obj->vptr->getArea(obj)
file_operations、COM 介面皆採用此模式。C 實現 OOP 是系統程式設計師的進階內功,手寫一套迷你物件模型能徹底消除對「類與虛函數」的魔法感,建立正確的記憶體與指標心智模型。