首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

用 C 語言實現面向對象程式設計 (一):極簡宏包 OOSM 核心架構

     編輯:關於C語言

動機:為什麼在 C 中做 OOP?

  • 理解物件導向本質:封裝、繼承、多態的底層機制
  • 嵌入式/核心開發:C++ 編譯器不可用或受限
  • 輕量級:無虛表開銷、無 RTTI、二進位體積極小
  • 教學價值:消除「C++ 魔法」迷思,建立正確心智模型

OOSM 宏包:<30 行核心實現

/* Object-Oriented Support Macros (OOSM)
 * 輕量級 C 面向對象支援宏包
 * 參考 LW_OOPC 精簡而來
 */
#ifndef __OOSM_H__
#define __OOSM_H__

#include <stdlib.h>

/* ===== 類別定義 ===== */
#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          // 實現介面:同樣嵌入

/* ===== 建構子/解構子宏 ===== */
#define constructor(type) \
    type* type##_new(void) { \
        type* this = (type*)malloc(sizeof(type)); \
        if (!this) return NULL; \
        type##_constructor(this); \
        return this; \
    } \
    void type##_constructor(type* this)

#define destructor(type) \
    void type##_delete(type* this) { \
        if (type##_destructor(this)) free(this); \
    } \
    int type##_destructor(type* this)

/* ===== 方法映射 ===== */
#define mapping(tf, sf)  this->tf = sf

#endif /* __OOSM_H__ */

宏展開範例:定義一個 Circle 類別

/* 使用 OOSM 定義 */
class(Circle) {
    implements(IShape);   // 實現介面
    double radius;
    double (*area)(Circle* this);  // 自有方法
};

/* 展開後等價於 */
typedef struct Circle Circle;
Circle* Circle_new(void);
void Circle_constructor(Circle* t);
int Circle_destructor(Circle* t);
void Circle_delete(Circle* t);
struct Circle {
    IShape IShape;        // 介面嵌入
    double radius;
    double (*area)(Circle* this);
};

介面定義:imeas.h

#ifndef __IMEAS_H__
#define __IMEAS_H__
#include "oosm.h"

interface(imeas) {
    double (*peri)(void* this);  // 周長
    double (*area)(void* this);  // 面積
};

#endif

關鍵點:介面方法第一參數用 void*,便於不同子類 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;  // 回傳 1 表示釋放記憶體
}

使用範例:多態呼叫

#include <stdio.h>
#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;  // 繼承自 crect

    /* 多態呼叫:介面方法統一入口 */
    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));
    printf("Square:    周長=%.2f 面積=%.2f\n", 
           s->crect.imeas.peri(s), s->crect.imeas.area(s));

    ccirc_delete(c);
    crect_delete(r);
    csqua_delete(s);
    return 0;
}

核心機制解析

機制C++ 對應OOSM 實現
封裝class + private結構體 + 紀律性命名(慣例 `_` 開頭)
繼承class Derived : Baseextends(Base) → 結構體首欄位嵌入父類
多態virtual 函數 + vtable函數指標欄位 + mapping 手動綁定
建構/解構ctor/dtorconstructor/destructor 宏生成 _new/_delete
介面abstract classinterface + implements 嵌入

局限與權衡

  • 無存取控制:C 無 private,靠命名慣例與程式碼審查
  • 手動 this 傳遞:c->imeas.peri(c) 需顯式傳 this
  • 單一繼承:extends 僅支援單一父類
  • 無 RTTI/例外:錯誤處理靠回傳碼或 setjmp/longjmp
  • 效能:函數指標間接呼叫,現代 CPU 分支預測影響微乎其微

適用場景

  • 微控制器裸機程式(裝置驅動、狀態機)
  • C 語言專案引入模組化架構
  • 教學示範:虛表、多態、建構子語意
  • 需極小二進位體積的庫開發
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved