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

純 C 語言實現面向對象:結構體內存佈局模擬繼承與封裝

     編輯:關於C語言

純 C 語言實現面向對象:結構體內存佈局模擬繼承與封裝

C 語言雖無內建類與繼承,但通過結構體內存佈局規則與巨集技巧,可實現語意上的繼承、封裝與多態基礎。本文從內存模型出發,逐步推導兩種繼承實現方式、方法封裝策略、虛函數表雛形,並討論工程落地的取捨。

1. 內存佈局視角的繼承本質

C++ 中子類物件包含父類子物件,內存連續分布:

[父類成員][子類自有成員]
^            ^
|            |
父類指針    子類指針(同一地址)

因此 Child* 隱式轉換為 Parent* 只需地址不變,直接訪問前段內存。

2. 結構體實現繼承的兩種方式

方式一:父類物件作為成員(組合模擬)

struct Parent { int x, y, z; };
struct Child { struct Parent parent; float f; char s[10]; };

訪問父類成員需 child.parent.x 或強轉 ((struct Parent*)&child)->x,語法冗長,非直觀。

方式二:子類展開所有父類成員(扁平化)

struct Child { int x, y, z; float f; char s[10]; };

訪問直接 child.x,但維護災難:父類增減欄位需同步修改所有子類。

3. 巨集解決維護難題

#define PARENT_FIELDS  int x; int y; int z

struct Parent { PARENT_FIELDS; };
struct Child  { PARENT_FIELDS; float f; char s[10]; };

多層繼承同理:

#define CHILD_FIELDS  PARENT_FIELDS; float f; char s[10]
#define GRAND_FIELDS  CHILD_FIELDS; double d

struct Grand { GRAND_FIELDS; };

4. 方法(成員函數)封裝與繼承

C 無成員函數,慣用「帶類型前綴的自由函數」模擬:

typedef struct Parent Parent;
void parent_method(Parent* self) { ... }

typedef struct Child Child;
void child_method(Child* self) {
    parent_method((Parent*)self); // 子類調用父類方法,需顯式強轉
    // 子類自有邏輯
}

5. 進階:函數指針表模擬虛函數表

為支援運行時多態,可在結構體內嵌函數指針表指針:

struct Parent_VTable {
    void (*method1)(Parent*);
    void (*method2)(Parent*, int);
};
const struct Parent_VTable parent_vtable = { parent_method1, parent_method2 };

struct Parent {
    PARENT_FIELDS;
    const struct Parent_VTable* vptr;
};

// 初始化
Parent* p = malloc(sizeof(Parent));
p->vptr = &parent_vtable;

// 調用
p->vptr->method1(p);

子類繼承時複製父類 vptr 並覆寫特定槽位,即構成簡易虛表機制。

6. 工程取捨:模擬到何種程度?

  • 不可模擬:private/protected 訪問控制、this 隱式參數、編譯器級多態、RTTI、異常處理。
  • 建議模擬:命名規約(Type_method)、結構體扁平化+巨集維護、關鍵多態點引入虛表指針。
  • 核心原則:不違背 C「程式設計師掌控一切、直接簡明」的哲學;若需完整 OO,請直接用 C++。

內存佈局圖

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved