本篇展示如何用 OOSM 定義介面、實作具體類別、達成執行期多態。
imeas.h — 測量周長與面積#ifndef __IMEAS_H__
#define __IMEAS_H__
#include "oosm.h"
/* 介面:純行為契約,無狀態 */
interface(imeas) {
double (*peri)(void* this); // 周長
double (*area)(void* this); // 面積
};
#endif
關鍵設計:方法第一參數用 void*,允許任意實作類別的 this 隱式轉換(類似 C++ 虛函數 this 指標調整)。
crect.h / crect.c/* crect.h */
#ifndef __CRECT_H__
#define __CRECT_H__
#include "imeas.h"
class(crect) {
implements(imeas); // 嵌入介面結構體
double width;
double height;
};
#endif
/* crect.c */
#include "crect.h"
static double peri(void* this) {
crect* r = (crect*)this;
return 2 * (r->width + r->height);
}
static double area(void* this) {
crect* r = (crect*)this;
return r->width * r->height;
}
constructor(crect) {
mapping(imeas.peri, peri);
mapping(imeas.area, area);
}
destructor(crect) {
return 1; // 釋放記憶體
}
ccirc.h / ccirc.c/* ccirc.h */
#ifndef __CCIRC_H__
#define __CCIRC_H__
#include "imeas.h"
class(ccirc) {
implements(imeas);
double radius;
double (*diam)(ccirc* this); // 自有方法:直徑
};
#endif
/* ccirc.c */
#include "ccirc.h"
#define PI 3.1415926
static double peri(void* this) {
ccirc* c = (ccirc*)this;
return 2 * PI * c->radius;
}
static double area(void* this) {
ccirc* c = (ccirc*)this;
return PI * c->radius * c->radius;
}
static double diam(ccirc* this) {
return 2 * this->radius;
}
constructor(ccirc) {
mapping(imeas.peri, peri);
mapping(imeas.area, area);
mapping(diam, diam); // 自有方法直接映射
}
destructor(ccirc) {
return 1;
}
#include
#include "imeas.h"
#include "ccirc.h"
#include "crect.h"
int main() {
ccirc* c = ccirc_new();
crect* r = crect_new();
c->radius = 9.23;
r->width = 23.09; r->height = 78.54;
/* 介面多態:統一呼叫介面方法 */
printf("Circle: 直徑=%.2f 周長=%.2f 面積=%.2f\n",
c->diam(c), c->imeas.peri(c), c->imeas.area(c));
printf("Rectangle: 周長=%.2f 面積=%.2f\n",
r->imeas.peri(r), r->imeas.area(r));
ccirc_delete(c);
crect_delete(r);
return 0;
}
記憶體佈局 (crect 實例): +------------------+ | imeas (介面) | ← 偏移量 0 | peri: &peri | | area: &area | +------------------+ | width: 23.09 | | height: 78.54 | +------------------+ 記憶體佈局 (ccirc 實例): +------------------+ | imeas (介面) | ← 偏移量 0 (關鍵!介面必須在首位) | peri: &peri | | area: &area | +------------------+ | radius: 9.23 | | diam: &diam | +------------------+ 多態呼叫 c->imeas.peri(c): 1. c 指向 ccirc 實例開頭 2. c->imeas 取得介面子物件 (偏移量 0) 3. imeas.peri 取得函數指標 &ccirc_peri 4. 呼叫 ccirc_peri(c) → this 為 ccirc*,內部轉型存取 radius
imeas 介面,不依賴具體類別this 指標無需調整即可轉為介面指標this 傳遞:c->imeas.peri(c) 需顯式傳入,C 無隱式 thisimplements 僅支援一個介面(可透過嵌套結構體擴展)_new 無參數,初始化需另行 init 方法將展示 extends(crect) 實現單一繼承,正方形作為矩形特化,覆寫周長/面積方法,構建完整類別體系。