在純 C 語言中實現面向對象核心特性:封裝、繼承、多型、建構子/解構子、介面。參考 LW_OOPC 簡化而成的 OOSM (Object-Oriented Support Macros) 宏包,僅 30 行核心巨集。
#ifndef __OOSM_H__
#define __OOSM_H__
#include
// 類別宣告:定義結構體 + 建構/解構函數原型
#define class(type) \
typedef struct type type; \
type* type##_new(void); \
void type##_constructor(type* t); \
int type##_destructor(type* t); \
void type##_delete(type* t); \
struct type
// 介面宣告:純虛函數表
#define interface(type) \
typedef struct type type; \
struct type
// 繼承:嵌入父類別結構體
#define extends(type) type type
// 實作介面:同繼承語法
#define implements(type) type type
// 建構子實作:分配記憶體 + 呼叫 constructor
#define constructor(type) \
type* type##_new(void) { \
type* this = (type*)malloc(sizeof(type)); \
if (this == NULL) return NULL; \
type##_constructor(this); \
return this; \
} \
void type##_constructor(type* this)
// 解構子實作:呼叫 destructor + 釋放記憶體
#define destructor(type) \
void type##_delete(type* this) { \
if (type##_destructor(this)) free(this); \
} \
int type##_destructor(type* this)
// 成員函數指標綁定:this->tf = sf
#define mapping(tf, sf) this->tf = sf
#endif
// 使用巨集定義
class(ccirc) {
extends(cbase); // 繼承基類
double radius; // 屬性
double (*diam)(ccirc*); // 方法指標
imes iam; // 介面實作
};
// 對應展開為:
typedef struct ccirc ccirc;
ccirc* ccirc_new(void);
void ccirc_constructor(ccirc* t);
int ccirc_destructor(ccirc* t);
void ccirc_delete(ccirc* t);
struct ccirc {
extends(cbase); // struct cbase cbase;
double radius;
double (*diam)(ccirc*);
imes iam;
};
#include
#include "imeas.h"
#include "ccirc.h"
#include "crect.h"
#include "csqua.h"
int main() {
ccirc* c = ccirc_new(); // 建構
crect* r = crect_new();
csqua* s = csqua_new();
c->radius = 9.23;
r->width = 23.09; r->height = 78.54;
s->crect.width = 200.00;
// 呼叫方法:需傳遞 this 指標
printf("Circle: (%lf, %lf, %lf)\n",
c->diam(c), c->iam.peri(c), c->iam.area(c));
printf("Rectangle: (%lf, %lf)\n",
r->iam.peri(r), r->iam.area(r));
printf("Square: (%lf, %lf)\n",
s->crect.iam.peri(s), s->crect.iam.area(s));
ccirc_delete(c); // 解構
crect_delete(r);
csqua_delete(s);
return 0;
}
struct child {
extends(parent); // 等價於 struct parent parent;
// 子類別成員...
};
// 父類別建構子
void parent_constructor(parent* this) {
this->method = parent_method;
}
// 子類別建構子
void child_constructor(child* this) {
parent_constructor((parent*)this); // 呼叫父建構子
this->method = child_method; // 覆寫方法指標
}
| 優點 | 缺點 |
|---|---|
| 極輕量(30 行巨集) | 無私有/保護成員(全 public) |
| 標準 C99 相容 | 需手動傳遞 this 指標 |
| 支援單繼承、介面、多型 | 繼承層級過深效能下降 |
| 零執行期開銷(純編譯期) | 無 RTTI、無例外處理 |
| 除錯較困難(巨集展開複雜) |
OOSM 展示了面向對象本質是「設計思想」而非「語言特性」。理解其運作原理,能深化對 C++ 物件模型(vtable、this 指標、建構/解構順序)的掌握。