C 語言無原生多態支援,但通過**函式指標**可構建完整的物件導向系統:封裝、繼承、多態。本文從簡單回調進化到工業級插件架構:虛函式表、表驅動、動態註冊,展示音頻解碼器實戰案例。
typedef enum { AAC, MPEG } AudioType;
void* AudioDecOpen(AudioType type) {
if(type == AAC) return aac_open();
else if(type == MPEG) return mpeg_open();
return NULL;
}
// 缺點:新增解碼器需修改此函式,違反開閉原則
// 介面定義:三個核心操作
typedef int (*OpenFunc)(void* this);
typedef int (*CloseFunc)(void* this);
typedef int (*ControlFunc)(void* this, int cmd, void* param);
// 虛函式表
typedef struct {
OpenFunc open;
CloseFunc close;
ControlFunc control;
} AudioModule;
// 物件結構:繼承介面 + 具體狀態
typedef struct {
AudioModule *vptr; // 虛函式表指標
int audio_type;
void *private_data; // 具體實現私有數據
} AudioDecoder;
// 具體模組實現
static int aac_open(void* this) { ... }
static int aac_close(void* this) { ... }
static int aac_control(void* this, int cmd, void* param) { ... }
static AudioModule aac_module = {
.open = aac_open,
.close = aac_close,
.control = aac_control
};
// 表驅動:類型 -> 模組映射
typedef struct {
AudioType type;
AudioModule *module;
} AudioPoolEntry;
AudioPoolEntry pool[] = {
{AAC, &aac_module},
{MPEG, &mpeg_module}
};
// 工廠函式
AudioDecoder* AudioCreate(AudioType type) {
AudioDecoder *dec = malloc(sizeof(AudioDecoder));
for(auto &e : pool) {
if(e.type == type) {
dec->vptr = e.module;
dec->audio_type = type;
dec->private_data = NULL;
break;
}
}
return dec;
}
// 多態調用
int AudioOpen(AudioDecoder *dec) {
return dec->vptr->open(dec);
}
#define MAX_POOL 32
static AudioPoolEntry pool[MAX_POOL];
static int pool_count = 0;
// 註冊介面:各模組初始化時自動調用
int AudioRegister(AudioType type, AudioModule *module) {
if(pool_count >= MAX_POOL) return -1;
pool[pool_count++] = (AudioPoolEntry){type, module};
return 0;
}
// AAC 模組自註冊
static int aac_init() {
return AudioRegister(AAC, &aac_module);
}
// 構造函式屬性:載入時自動執行 (GCC/Clang)
__attribute__((constructor)) static void aac_auto_register() {
aac_init();
}
**優勢**:新增解碼器只需編譯鏈接,無需修改核心代碼,支援動態載入 .so/.dll。
// AAC 解碼器私有數據
typedef struct {
NeAACDecHandle hDecoder;
pthread_t decoder_thread;
bool exit_flag;
} AacPrivate;
static int aac_close(void* this) {
AudioDecoder *dec = (AudioDecoder*)this;
AacPrivate *priv = (AacPrivate*)dec->private_data;
if(!priv) return -1;
priv->exit_flag = true;
if(priv->decoder_thread) pthread_join(priv->decoder_thread, NULL);
if(priv->hDecoder) NeAACDecClose(priv->hDecoder);
free(priv);
dec->private_data = NULL;
return 0;
}
static int aac_control(void* this, int cmd, void* param) { return 0; }
static AudioModule aac_module = {
.open = aac_open,
.close = aac_close,
.control = aac_control
};
__attribute__((constructor)) static void register_aac() {
AudioRegister(AAC, &aac_module);
}
| 架構 | 擴展性 | 執行期開銷 | 適用場景 |
|---|---|---|---|
| 硬編碼 if-else | 差 | 極低 | 固定少量類型 |
| 虛函式表 + 靜態表 | 中 (重編譯) | 1 次間接呼叫 | 嵌入式、固定模組 |
| 動態註冊 + 構造函式 | 優 (無侵入) | 1 次間接呼叫 | 插件系統、動態載入 |
| C++ virtual | 語言級支援 | 1 次間接呼叫 | 大型 C++ 專案 |
AudioModule 封裝演算法族AudioCreate 封裝建立邏輯AudioDecoder 僅依賴抽象 AudioModuleC 語言通過「函式指標 + 結構體 + 表驅動 + 動態註冊」可構建媲美 C++ 的多態系統。核心思想:**將「做什麼」 (介面) 與「怎麼做」 (實現) 分離,透過指標間接呼叫實現執行期綁定**。這正是面向對象設計在系統級編程中的精髓體現。