首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C++ 使用者定義型別轉換:轉換函數、建構函數、explicit、多重轉換陷阱

     編輯:VC 教學

動機

讓自訂類別 (如 SmallInt) 能隱式參與內建型別 (int, double) 的運算,避免為每種運算子重載提供所有組合 (如 operator+ 需 6 個版本支援 SmallInt+int, int+SmallInt, SmallInt+SmallInt 等)。

轉換函數

語法

class SmallInt {
    int val;
public:
    SmallInt(int i = 0) : val(i) {}
    // 型別轉換函數:無返回型別、無參數
    operator int() const { return val; }  // SmallInt -> int
    operator double() const { return val; } // SmallInt -> double
};

限制

  • 必須為**非靜態成員函數**。
  • **不能宣告返回型別** (編譯器依函數名推導)。
  • **不能有參數**。
  • 可加 const (不修改物件)。
  • 可加 explicit (C++11) 防止隱式轉換,僅允許 static_cast/扁式轉換。

調用時機

  1. 隱式轉換:SmallInt si(5); int i = si; // 調用 operator int()
  2. 引數匹配:void f(int); f(si); // 調用 operator int()
  3. 運算子運算元:si + 3 // si 轉 int 後執行 int+int

建構函數作為轉換 (單引數建構函數)

class Number {
public:
    Number(const SmallInt& si);  // SmallInt -> Number (隱式)
    explicit Number(double d);   // double -> Number (僅顯式)
};
  • 單引數建構函數 (或除第一參數外皆有預設值) 定義了**從引數型別到類別的隱式轉換**。
  • 加 explicit 禁止隱式轉換,僅允許直接初始化/強制轉換。

標準轉換序列配合

若轉換函數目標型別與需求型別不完全匹配,但可經**標準轉換**到達,編譯器仍會調用:


extern void calc(double);
SmallInt si(10);
calc(si);  // 1. si.operator int() → int
           // 2. int → double (標準轉換)
           // 調用 calc(double)

多重轉換陷阱 (Ambiguity)


class A { public: operator int() const; };
class B { public: B(int); };  // 隱式轉換建構函數

void f(int);
void f(B);

A a;
f(a);  // 錯誤:Ambiguous
       // 路徑1: A::operator int() → f(int)
       // 路徑2: A::operator int() → int → B(int) → f(B)

解決

  • 移除多餘轉換路徑 (加 explicit、刪除轉換函數/建構函數)。
  • 使用 static_cast 明確指定路徑。

最佳實踐

  1. 預設加 explicit 於單引數建構函數與轉換函數 (C++11),除非極確定隱式轉換符合領域邏輯且無歧義 (如智慧指標 operator bool())。
  2. 提供 to_string(), to_int() 等**顯式命名函數** 替代隱式轉換,提高可讀性。
  3. 避免雙向隱式轉換 (A→B 且 B→A) 導致無限遞迴/歧義。
  4. 轉換函數標記 const,確保不修改物件狀態。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved