第九講聚焦泛型編程:以「算法為脊,數據為肉」,通過參數多態實現算法對數據結構的最大程度解耦與復用。從 max 函式模板到 STL 三大件(算法、容器、迭代器),冒號老師展示泛型思維如何穿透表象,提煉出「對指定集合中滿足條件的元素執行操作」的通用抽象。
一、泛型編程核心主張
- 分離關注點:算法(做什麼)與數據結構(裝什麼)正交分離。
- 參數多態:
template <typename T> 或 Class<T>,編譯期具現化,零執行期開銷。
- 優於繼承多態:OOP 子型多態需繼承體系、虛函式表分派;GP 無侵入、無繼承、靜態綁定,效能更高、適用面更廣。
二、經典對比:max 函式
// C++ 模板:類型安全、支援運算符重載、編譯期內聯
template <typename T>
T max(T a, T b) { return (a > b) ? a : b; }
// C 宏:無類型檢查、副作用風險、無法除錯
#define max(a,b) ((a) > (b) ? (a) : (b))
模板版本可作用於任何定義 operator> 的類型(整數、浮點、字串、自訂類),真正實現「一舉 N 得,N 趨向無窮大」。
三、Java 與 void* 的類型安全陷阱
- Java Object 統一:基本類型需裝箱/拆箱,損失效能;取出時需強制轉型,編譯期失去類型保護,執行期才拋
ClassCastException。
- C/C++ void*:同樣丟失類型資訊,需人工轉型,極易出錯。
- 泛型本質:在靜態類型系統內保留類型參數至編譯期,兼得安全與復用。
四、STL 三要素與泛型抽象層次
| 要素 | 角色 | 抽象對應 |
| 算法 | 操作邏輯 | 脊梁 |
| 容器 | 數據集合 | 肉體 |
| 迭代器 | 算法與容器的介面 | 抽象指標/游標 |
五、從六道題目看泛型共性
冒號老師列舉六道看似無關的題目:
- 整數陣列隨機取十數,質數求和
- 無序集合中完全平方數換為平方根
- 成績表篩選全科及格且平均 > 70 的學生
- 著色二元樹中紅節點改藍
- 字串從倒數第三字元反向拷貝
- 標準輸入讀非數字字元則提示
共同本質:對指定範圍內滿足條件的元素執行指定操作。
泛型實現:
template <class Iterator, class Act, class Test>
void process(Iterator begin, Iterator end, Act act, Test test) {
for (; begin != end; ++begin)
if (test(*begin)) act(*begin);
}
Iterator:泛化容器存取方式(陣列、鏈表、樹、輸入流均可)。
Act:泛化處理動作(函式、函子、Lambda)。
Test:泛化篩選條件。
- 元素類型
T 隱藏於迭代器解引用 *begin 中,容器類型完全消失。
六、迭代器的隱性泛化
迭代器不僅統一存取語法,更抽象遍歷策略:
- 前向、雙向、隨機存取、輸入/輸出迭代器分類。
- 自訂遍歷順序(層序、中序、跳躍式)。
標準輸入流 std::cin 同樣可視為容器,istream_iterator 使題目 6 納入同一框架。
七、泛型思維的數學淵源
「數學家證明定理後,總試圖在保持核心思想下放寬條件、增強結論,推廣定理。思想是雞,結論是蛋。」—— Alexander Stepanov (STL 之父) 擁有數學背景並非巧合。
泛型編程是算法導向:以算法為中心,逐步模糊數據結構內涵、擴大外延。這不只是技巧,而是用新視角審視問題的方法論。
- 上一篇文章: 冒號與他的學生們(連載 10):超級範式——元編程
- 下一篇文章: 冒號與他的學生們(八):併發範式——在競爭中合作
Copyright ©
程式碼之家 All Rights Reserved