C 無類/繼承,但可用結構體封裝數據、函數指針封裝行為、父結構體作為子結構體首字段實現單繼承多態。
/***** 父類:Shape *****/
typedef struct Shape {
void (*print)(void); // 虛函數
float (*area)(struct Shape *); // 虛函數帶 this 指針
} Shape;
/***** 子類:Square *****/
typedef struct Square {
Shape base; // 必須是第一個成員!內存佈局兼容父類
float width;
float height;
} Square;
/***** 子類:Circle *****/
typedef struct Circle {
Shape base;
float radius;
} Circle;
/***** 子類:Triangle *****/
typedef struct Triangle {
Shape base;
float base_len;
float height;
} Triangle;
/***** Square 實現 *****/
void square_print(void) { printf("Hello Square\n"); }
float square_area(Shape *this) {
Square *sq = (Square *)this; // 向下轉型
return sq->width * sq->height;
}
void square_ctor(Square *sq, float w, float h) {
sq->width = w; sq->height = h;
sq->base.print = square_print;
sq->base.area = square_area;
}
/***** Circle 實現 *****/
void circle_print(void) { printf("Hello Circle\n"); }
float circle_area(Shape *this) {
Circle *c = (Circle *)this;
return 3.14159f * c->radius * c->radius;
}
void circle_ctor(Circle *c, float r) {
c->radius = r;
c->base.print = circle_print;
c->base.area = circle_area;
}
/***** Triangle 實現 *****/
void triangle_print(void) { printf("Hello Triangle\n"); }
float triangle_area(Shape *this) {
Triangle *t = (Triangle *)this;
return 0.5f * t->base_len * t->height;
}
void triangle_ctor(Triangle *t, float b, float h) {
t->base_len = b; t->height = h;
t->base.print = triangle_print;
t->base.area = triangle_area;
}
int main() {
Square sq; square_ctor(&sq, 3.0f, 4.0f);
Circle ci; circle_ctor(&ci, 2.5f);
Triangle tr; triangle_ctor(&tr, 3.0f, 4.0f);
Shape *shapes[] = { (Shape *)&sq, (Shape *)&ci, (Shape *)&tr };
int n = 3;
for (int i = 0; i < n; i++) {
shapes[i]->print(); // 動態分發
printf("Area = %.2f\n\n", shapes[i]->area(shapes[i]));
}
return 0;
}
Hello Square Area = 12.00 Hello Circle Area = 19.63 Hello Triangle Area = 6.00
Square 內存: +------------------+ <-- &sq (也是 &sq.base) | Shape.base.print | offset 0 | Shape.base.area | offset 8 (64位) / 4 (32位) +------------------+ | width | offset 16/8 | height | offset 20/12 +------------------+ Shape* 指向 sq 時,取 offset 0,8 正好是 print/area 指針 若 base 不是首字段,指針偏移錯誤 → 崩潰
/***** 共享 vtable *****/
typedef struct { void (*print)(void); float (*area)(Shape*); } ShapeVTable;
ShapeVTable square_vtable = { square_print, square_area };
ShapeVTable circle_vtable = { circle_print, circle_area };
typedef struct Shape2 { const ShapeVTable *vptr; } Shape2;
typedef struct Square2 { Shape2 base; float w, h; } Square2;
void square2_ctor(Square2 *s, float w, float h) {
s->w = w; s->h = h;
s->base.vptr = &square_vtable;
}
/* 調用 */
((Shape2 *)&sq2)->vptr->print();
((Shape2 *)&sq2)->vptr->area((Shape2 *)&sq2);
優點:每對象只存一個 vptr,方法不重複;缺點:構造時需手動綁定 vptr。
enter/exit/handle 為虛函數file_operations、block_device_operations (Linux 內核)Widget 基類,Button/Label/Window 子類C 實現多態三板斧:父結構體首字段嵌入、函數指針作為虛函數、構造函數綁定具體實現。理解內存佈局與指針轉型,即可在 C 中構建靈活、高性能的面向對象框架。