面對大量 if-else 或 switch-case 分支,程式碼會變得臃腫難維護。C++ 提供函數指標與成員函數指標機制,配合 std::map 或陣列建立「鍵值→函數」映射,實現 O(log N) 或 O(1) 分派。本文完整示範兩種策略並比較優劣。
enum type_func {
type_begin = -1,
type_eat, type_sleep, type_walk, type_run,
type_smile, type_cry, type_jump,
type_max_size
};
class CAnimal {
public:
typedef int (CAnimal::*ptr_func)(bool); // 成員函數指標型別
protected:
static std::map s_map; // Map 策略
static ptr_func s_array[type_max_size]; // Array 策略
public:
CAnimal() {
memset(s_array, 0, sizeof(s_array));
Init();
}
// ... 七個行為函數:eat, sleep, walk, run, smile, cry, jump
// 皆回傳 int,參數 bool,預設 true
};
void CAnimal::Init() {
// Map 映射
s_map[type_eat] = &CAnimal::eat;
s_map[type_sleep] = &CAnimal::sleep;
s_map[type_walk] = &CAnimal::walk;
s_map[type_run] = &CAnimal::run;
s_map[type_smile] = &CAnimal::smile;
s_map[type_cry] = &CAnimal::cry;
s_map[type_jump] = &CAnimal::jump;
// Array 映射(索引對應 enum 值)
s_array[type_eat] = &CAnimal::eat;
s_array[type_sleep] = &CAnimal::sleep;
s_array[type_walk] = &CAnimal::walk;
s_array[type_run] = &CAnimal::run;
s_array[type_smile] = &CAnimal::smile;
s_array[type_cry] = &CAnimal::cry;
s_array[type_jump] = &CAnimal::jump;
}
// 靜態成員定義(放在類別外)
std::map CAnimal::s_map;
CAnimal::ptr_func CAnimal::s_array[type_max_size];
void Process(type_func type) {
switch (type) {
case type_eat: eat(); break;
case type_sleep: sleep(); break;
// ...
}
}
優點:直觀;缺點:分支多時臃腫、擴充需修改核心邏輯、O(N) 線性比對。
void ProcessByUseMap(int key, bool val) {
auto it = s_map.find(static_cast(key));
if (it != s_map.end()) {
ptr_func pFun = it->second;
if (pFun) (this->*pFun)(val);
}
}
優點:動態擴充、鍵值不需連續、O(log N) 查找;缺點:記憶體開銷大(紅黑樹節點)、需包含 <map>。
void ProcessByUseArray(int key, bool val) {
if (type_begin < key && key < type_max_size) {
ptr_func pFun = s_array[key];
if (pFun) (this->*pFun)(val);
}
}
優點:O(1) 直接索引、記憶體緊湊、無動態分配;缺點:enum 值必須連續、擴充需調整陣列大小與 enum 定義。
// Map 版 operator[]
int operator[](int key) {
auto it = s_map.find(static_cast(key));
if (it != s_map.end()) {
ptr_func pFun = it->second;
if (pFun) return (this->*pFun)(false);
}
return NULL;
}
// Array 版 operator()
int operator()(int key, bool val) {
if (type_begin < key && key < type_max_size) {
ptr_func pFun = s_array[key];
if (pFun) return (this->*pFun)(val);
}
return NULL;
}
使用方式:
CAnimal dog;
dog[type_eat]; // Map 版,預設 false
dog(type_run, true); // Array 版,傳 true
void func_eat(int = 0) {}
void func_run(int = 0) {}
// ...
typedef void (*ptrFun)(int);
std::map g_map;
ptrFun g_array[type_max_size];
// 初始化
g_map[type_eat] = func_eat;
g_array[type_eat] = func_eat;
// 使用
g_map[type_eat](1);
g_array[type_run](2);
| 指標 | Map | Array | Switch |
|---|---|---|---|
| 查找複雜度 | O(log N) | O(1) | O(N) |
| 記憶體開銷 | 高(樹節點) | 低(連續陣列) | 極低 |
| 鍵值連續性 | 不需連續 | 必須連續 | 不需連續 |
| 動態擴充 | 容易 | 麻煩(需改 enum/陣列) | 麻煩 |
| 適用場景 | 插件系統、動態註冊、稀疏鍵值 | 高頻熱路徑、固定協定、效能關鍵 | 分支少、邏輯簡單 |
本文著重 Map/Array 兩種指標映射。若需更強的型別安全與擴充性,可定義抽象介面 IAction,每個行為實作一個類別,配合 Factory 模式管理。此為策略模式,屬於物件導向層面的解法,不在本文範圍內。