函數重載是 C++ 最基礎也最常用的特性之一,但背後的編譯器機制往往被忽略。本文從「命名衝突如何解決」與「呼叫如何綁定」兩大核心問題切入,系統闡述 Name Mangling、呼叫匹配規則、多載解析三階段流程,並補充模板與普通函數的重載互動規則,助你建立完整的編譯期視角。
同一作用域內,同名函數擁有不同參數列表(型別、個數、順序),構成重載集合。返回型別不參與重載區分。典型用例:print(int)、print(string)、建構子多載、運算子重載等。
| 原始宣告 | Mangled Symbol |
|---|---|
void print(int) | _Z5printi |
void print(std::string) | _Z5printSs |
int max(int,int) | _Z3maxii |
double max(double,double) | _Z3maxdd |
class Test::print(int) | _ZN4Test5printEi |
規律:_Z 前綴 → 長度+函數名 → 編碼後的參數型別。成員函數額外包含 N<長度><類別名> 表示作用域。
若允許 float sqrt(float) 與 double sqrt(double) 共存,呼叫 sqrt(da) 時編譯器無法在不依賴上下文(指派目標型別)的情況下決定呼叫哪一個,違反「呼叫解析獨立於上下文」原則。
const)。bool/char/short → int)、float → double。int→double、Derived*→Base*、T*→void* 等。... 參數。若最高優先層級出現多個可行函數 → 模稜兩可 → 編譯錯誤。
private/protected 亦視為可見,但後續會因存取權被拒)。friend 函數對每個可用函數,依參數位置給予匹配等級權重(精確 > 提升 > 標準 > 使用者定義 > 省略號),總分最高者勝出。若並列最高 → 錯誤。
依 C++ 標準(Bjarne Stroustrup 表述):
using 宣告而非 using namespace,減少 ADL 意外納入。explicit 單引數建構子,避免隱式轉換干擾多載解析。函數重載看似語法糖,實則涉及符號表管理、型別系統、作用域規則、模板特化排序等核心編譯器技術。深入理解其運作機制,不僅能解開疑難編譯錯誤,更能設計出更清晰、更安全的 API。