《C++箴言:聲明為非成員函數的時機》闡述了為什么只有 non-member functions(非成員函數)適合于應用到所有 arguments(實參)的 implicit type conversions(隱式類型轉換),而且它還作為一個示例使用了一個 Rational class 的 Operator* function。我建議你在閱讀本文之前先熟悉那個示例,因為本文進行了針對《C++箴言:聲明為非成員函數的時機》中的示例做了一個無傷大雅(模板化 Rational 和 operator*)的擴展討論:
template<typename T> class Rational { public: Rational(const T& numerator = 0, // see《C++箴言:用傳引用給const取代傳值》for why params const T& denominator = 1); // are now passed by reference
const T numerator() const; // see《C++箴言:避免返回對象內部構件的句柄》for why return const T denominator() const; // values are still passed by value, ... // Item 3 for why they're const };
friend const Rational operator*(const Rational& lhs, const Rational& rhs) { return Rational(lhs.numerator() * rhs.numerator(), // same impl lhs.denominator() * rhs.denominator()); // as in } //《C++箴言:聲明為非成員函數的時機》 }; 確實,這樣就可以符合預期地工作:對 operator* 的混合模式調用現在可以編譯,連接,并運行。萬歲!
關于此技術的一個有趣的觀察結論是 friendship 的使用對于訪問 class 的 non-public parts(非公有構件)的需求并沒有起到什么作用。為了讓所有 arguments(實參)的 type conversions(類型轉換)成為可能,我們需要一個 non-member function(非成員函數)(《C++箴言:聲明為非成員函數的時機》 依然適用);而為了能自動實例化出適當的函數,我們需要在 class 內部聲明這個函數。在一個 class 內部聲明一個 non-member function(非成員函數)的唯一方法就是把它做成一個 friend(友元)。那么這就是我們做的。反傳統嗎?是的。有效嗎?毫無疑問。
就像《C++箴言:理解inline化的介入和排除》闡述的,定義在一個 class 內部的函數被隱式地聲明為 inline(內聯),而這也包括像 operator* 這樣的 friend functions(友元函數)。你可以讓 operator* 不做什么事情,只是調用一個定義在這個 class 之外的 helper function(輔助函數),從而讓這樣的 inline declarations(內聯聲明)的影響最小化。在本文的這個示例中,沒有非凡指出這樣做,因為 operator* 已經可以實現為一個 one-line function(單行函數),但是對于更復雜的函數體,這樣做也許是合適的。"have the friend call a helper"(“讓友元調用輔助函數”)的方法還是值得注重一下的。
·在寫一個提供了 class template(類模板),而這個 class template(類模板)提供了一個函數,這個函數指涉到支持所有 parameters(參數)的 implicit type conversions(隱式類型轉換)的 template(模板)的時候,把這些函數定義為 class template(類模板)內部的 friends(友元)。