當我們設計一個像 SmallInt 這樣的類別時,若希望它能與內建算術型別(如 int)或同類別物件進行加減運算,傳統做法必須撰寫大量運算子多載函式。以 SmallInt 為例,僅支援基本加減就需要 6 個運算子函式:兩個成員運算子處理 SmallInt 之間的運算,四個友元全域運算子處理與 int 的混合運算。若再加上位元、邏輯、關係與複合指派運算子,所需函式數量將呈指數級增長,維護難度極高。
C++ 提供了更優雅的解決方案:使用者定義型別轉換。透過定義轉換函式,讓類別物件能自動轉換為目標型別(如 int),編譯器會在需要時隱式呼叫,從而避免大量運算子多載。
轉換函式是一種特殊的成員函式,語法如下:
class SmallInt {
public:
SmallInt(int ival) : value(ival) {}
// 轉換操作符:SmallInt → int
operator int() { return value; }
private:
int value;
};
關鍵限制:
錯誤示範:
operator int(SmallInt &); // 錯誤:非成員函式
int operator int(); // 錯誤:指定回傳型別
operator int(int = 0); // 錯誤:帶有參數列
使用函式式轉換或 static_cast 時會明確呼叫轉換函式:
Token tok("function", 78);
SmallInt tokVal = SmallInt(tok); // 呼叫 Token::operator SmallInt()
char* tokName = static_cast(tok); // 呼叫 Token::operator char*()
當轉換目標型別與轉換函式回傳型別不完全匹配,但可透過標準轉換到達時,編譯器仍會呼叫轉換函式:
extern void calc(double);
Token tok("constant", 44);
calc(tok); // 1. 呼叫 tok.operator int() → 2. int 標準轉換為 double
單引數建構函數(非 explicit)也可作為隱式轉換:
extern void func(Number);
SmallInt si(87);
func(si); // 呼叫 Number(const SmallInt&) 建構函數
若需禁止隱式轉換,可在建構函數前加上 explicit 關鍵字。
explicit:C++11 起可將轉換函式標記為 explicit,僅允許顯式轉換使用者定義型別轉換是 C++ 強大的機制,能大幅減少運算子多載數量,提升程式碼可讀性與維護性。但需權衡便利性與型別安全,善用 explicit 控制隱式轉換行為,才能寫出健壯的 C++ 程式碼。