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

Effective C++ 條款 46:類模板中定義非成員函數以支持隱式類型轉換

     編輯:關於C++

問題背景

Item 24 指出:若所有參數都需隱式轉換,函數應為非成員函數。推廣到模板:

template <typename T>
class Rational {
public:
    Rational(const T& num = 0, const T& den = 1);
    const T numerator() const;
    const T denominator() const;
};

template <typename T>
const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs);

調用 Rational<int> r = oneHalf * 2; 失敗!編譯器無法從 2 推導模板參數 T(需先實例化函數模板,再考慮隱式轉換,兩階段矛盾)。

解決方案:友元函數定義於類內

template <typename T>
class Rational {
public:
    // 友元聲明 + 定義合一
    friend const Rational operator*(const Rational& lhs, const Rational& rhs) {
        return Rational(lhs.numerator() * rhs.numerator(),
                        lhs.denominator() * rhs.denominator());
    }
    // ... 其他成員
};

關鍵點:

  1. 類模板實例化時 T 已知,友元函數簽名固定為 Rational<T>,編譯器可直接匹配。
  2. 隱式轉換發生在函數調用時(第二階段),此時函數已實例化完成。
  3. 友元函數定義於類內 → 隱式 inline,適用簡短函數。

大型函數:轉發輔助函數

若函數體較大,不宜內聯,可轉發外部輔助模板:

template <typename T> class Rational; // 前置聲明
template <typename T>
const Rational<T> doMultiply(const Rational<T>&, const Rational<T>&); // 輔助

template <typename T>
class Rational {
public:
    friend const Rational operator*(const Rational& lhs, const Rational& rhs) {
        return doMultiply(lhs, rhs); // 轉發,此處 T 已知
    }
};

doMultiply 不支持混合模式,但只被內部 operator* 調用,參數已統一為 Rational<T>。

總結模式

場景方案關鍵
非模板類非成員友元函數Item 24
類模板,簡短函數類內友元定義隱式 inline
類模板,複雜函數類內友元轉發外部輔助模板分離接口與實現

深層原理

C++ 編譯流程:模板實例化 → 函數簽名確定 → 參數匹配(含隱式轉換)。友元定義於類內,實例化類時同步實例化友元函數,打破「推導模板參數需先知函數簽名」的死循環。

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