| 特性 | 面向物件 (OOP) | 泛型編程 (Templates) |
|---|---|---|
| 介面形式 | 顯式介面 (函數簽名:名稱、參數、回傳、const) | 隱式介面 (合法運算式集合) |
| 多態機制 | 執行期多態 (虛函數動態綁定) | 編譯期多態 (模板具現化 + 多載解析) |
| 型別檢查 | 編譯期依介面檢查 | 編譯期依運算式有效性檢查 |
// OOP 版本
void doProcessing(Widget& w) {
if (w.size() > 10 && w != someNastyWidget) {
Widget temp(w); temp.normalize(); temp.swap(w);
}
}
// Template 版本
template
void doProcessing(T& w) {
if (w.size() > 10 && w != someNastyWidget) {
T temp(w); temp.normalize(); temp.swap(w);
}
}
T 必須支援的隱式介面由模板內實際使用的運算式決定:
w.size() → 需有 size() 成員函數,回傳型別支援 operator>(int)。w != someNastyWidget → 需 operator!= 比較 T 與 someNastyWidget 型別 (可隱式轉換)。T temp(w) → 需拷貝建構函數。temp.normalize(), temp.swap(w) → 需對應成員函數。關鍵洞見: 介面非由簽名定義,而由「這些運算式能否編譯通過」定義。
size() 甚至不需回傳整數,只要回傳型別 X 滿足 X > int 即可 (可透過轉換、多載達成)。
T 具現化出不同函數實體。operator>, operator!=, swap) 經由重載解析 綁定至最佳匹配。
if (w.size() > 10 && w != someNastyWidget)
這個布爾運算式對 T 的完整約束極難窮盡列舉 (涉及 size, operator>, operator&&, operator!=, 隱式轉換鏈...),但整體約束極簡單:運算式必須可隱式轉換為 bool。
隱式介面雖由複雜運算式構成,實際約束往往直觀易懂。
走起來像鴨、叫起來像鴨 → 就是鴨 (滿足運算式即符合介面)。static_assert、Concepts (C++20) 明確約束與提升錯誤訊息可讀性。模板將「介面」從「簽名契約」昇華為「運算式語義契約」,將「多態」從「執行期查表」前移至「編譯期生成專屬代碼」,這是 C++ 泛型編程威力的源頭。