面向對象的核心——封裝、繼承、多態——本質是軟件工程管理複雜性的思想,不依賴特定語言。在C中通過不透明指針+函數指針表可實現接口與實現分離,達到「依賴抽象而非具體」的設計目標。
/* shape.h —— 抽象接口層 */
typedef struct shape_t {
void *shapeData; // 私有數據(不透明指針)
void (*area)(void *); // 計算面積
void (*release)(void *); // 釋放資源
} Shape;
/* circle.h —— 具體類型聲明 */
typedef struct { double r; } CircleData; // 私有數據結構
typedef struct {
void *shapeData;
void (*area)(void *);
void (*release)(void *);
} Circle;
Circle *makeCircle(double r); // 工廠函數
/*** circle.c —— 具體實現 ***/
static void area(void *shape) {
Circle *c = (Circle *)shape;
CircleData *d = (CircleData *)c->shapeData;
printf("circle area: %f\n", d->r * d->r * 3.14159);
}
static void release(void *shape) {
Circle *c = (Circle *)shape;
free(c->shapeData);
free(c);
}
Circle *makeCircle(double r) {
CircleData *d = malloc(sizeof(CircleData));
Circle *c = malloc(sizeof(Circle));
d->r = r;
c->shapeData = d;
c->area = area;
c->release = release;
return c;
}
關鍵點:
static修飾內部函數,實現私有方法CircleData僅在.c文件中定義,外部不可見(封裝)void printShapeArea(Shape **shapes, int n) {
for (int i = 0; i < n; ++i) {
shapes[i]->area(shapes[i]); // 多態調用
shapes[i]->release(shapes[i]); // 統一釋放
}
}
int main() {
Shape *list[3] = {
(Shape *)makeCircle(3.2),
(Shape *)makeCircle(1.5),
(Shape *)makeSquare(3.1, 4.0)
};
printShapeArea(list, 3); // 無需知曉具體類型
return 0;
}
只需提供triangle.h/.c實現同樣接口,printShapeArea完全不變。這正是開閉原則在C語言中的體現。
| OO概念 | C語言映射 |
|---|---|
| 類 | 結構體 + 函數指針表 |
| 封裝 | 不透明指針 + 內部靜態函數 |
| 繼承 | 結構體嵌套(組合優於繼承) |
| 多態 | 統一接口簽名 + 運行時函數指針綁定 |
| 構造/析構 | 工廠函數 / release回調 |