亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C++箴言:類型轉換時定義非成員函數

2019-11-17 05:12:38
字體:
來源:轉載
供稿:網友

  《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
};

template<typename T>
const Rational<T> operator*(const Rational<T>& lhs,
const Rational<T>& rhs)
{ ... }
  就像在《C++箴言:聲明為非成員函數的時機》中,我想要支持 mixed-mode arithmetic(混合模式運算),所以我們要讓下面這些代碼能夠編譯。我們指望它能,因為我們使用了和 Item 24 中可以工作的代碼相同的代碼。僅有的區別是 Rational 和 operator* 現在是 templates(模板):

Rational<int> oneHalf(1, 2); // this example is from 《C++箴言:聲明為非成員函數的時機》,
// except Rational is now a template

Rational<int> result = oneHalf * 2; // error! won't compile
  編譯失敗的事實暗示對于模板化 Rational 來說,有某些東西和 non-template(非模板)版本不同,而且確實存在。在《C++箴言:聲明為非成員函數的時機》中,編譯器知道我們想要調用什么函數(取得兩個 Rationals 的 operator*),但是在這里,編譯器不知道我們想要調用哪個函數。作為替代,它們試圖斷定要從名為 operator* 的 template(模板)中實例化出(也就是創建)什么函數。它們知道它們假定實例化出的某個名為 operator* 的函數取得兩個 Rational<T> 類型的參數,但是為了做這個實例化,它們必須斷定 T 是什么。問題在于,它們做不到。

  在推演 T 的嘗試中,它們會察看被傳入 operator* 的調用的 arguments(實參)的類型。在當前情況下,類型為 Rational<int>(oneHalf 的類型)和 int(2 的類型)。每一個參數被分別考察。

  使用 oneHalf 的推演很簡單。operator* 的第一個 parameter(形參)被聲明為 Rational<T> 類型,而傳入 operator* 的第一個 argument(實參)(oneHalf) 是 Rational<int> 類型,所以 T 一定是 int。不幸的是,對其它參數的推演沒那么簡單。operator* 的第二個 parameter(形參)被聲明為 Rational<T> 類型,但是傳入 operator* 的第二個 argument(實參)(2) 的 int 類型。在這種情況下,讓編譯器如何斷定 T 是什么呢?你可能期望它們會使用 Rational<int> 的 non-eXPlicit constrUCtor(非顯式構造函數)將 2 轉換成一個 Rational<int>,這樣就使它們推演出 T 是 int,但是它們不這樣做。它們不這樣做是因為在 template argument deduction(模板實參推演)過程中從不考慮 implicit type conversion functions(隱式類型轉換函數)。從不。這樣的轉換可用于函數調用過程,這沒錯,但是在你可以調用一個函數之前,你必須知道哪個函數存在。為了知道這些,你必須為相關的 function templates(函數模板)推演出 parameter types(參數類型)(以便你可以實例化出合適的函數)。但是在 template argument deduction(模板實參推演)過程中不考慮經由 constructor(構造函數)調用的 implicit type conversion(隱式類型轉換)。《C++箴言:聲明為非成員函數的時機》不包括 templates(模板),所以 template argument deduction(模板實參推演)不是一個問題,現在我們在 C++ 的 template 部分,這是主要問題。

  在一個 template class(模板類)中的一個 friend declaration(友元聲明)可以指涉到一個特定的函數,我們可以利用這一事實為受到 template argument deduction(模板實參推演)挑戰的編譯器解圍。這就意味著 class Rational<T> 可以為 Rational<T> 聲明作為一個 friend function(友元函數)的 operator*。class templates(類模板)不依靠 template argument deduction(模板實參推演)(這個過程僅適用于 function templates(函數模板)),所以 T 在 class Rational<T> 被實例化時總是已知的。通過將適當的 operator* 聲明為 Rational<T> class 的一個 friend(友元)使其變得輕易:


template<typename T>
class Rational {
public:
...
friend // declare operator*
const Rational operator*(const Rational& lhs, // function (see
const Rational& rhs); // below for details)
};

template<typename T> // define operator*
const Rational<T> operator*(const Rational<T>& lhs, // functions
const Rational<T>& rhs)
{ ... }
  現在我們對 operator* 的混合模式調用可以編譯了,因為當 object oneHalf 被聲明為 Rational<int> 類型時,class Rational<int> 被實例化,而作為這一過程的一部分,取得 Rational<int> parameters(形參)的 friend function(友元函數)operator* 被自動聲明。作為已聲明函數(并非一個 function template(函數模板)),在調用它的時候編譯器可以使用 implicit conversion functions(隱式轉換函數)(譬如 Rational 的 non-explicit constructor(非顯式構造函數)),而這就是它們如何使得混合模式調用成功的。

  唉,在這里的上下文中,“成功”是一個可笑的詞,因為盡管代碼可以編譯,但是不能連接。但是我們過一會兒再處理它,首先我想討論一下用于在 Rational 內聲明 operator* 的語法。

  在一個 class template(類模板)內部,template(模板)的名字可以被用做 template(模板)和它的 parameters(參數)的縮寫,所以,在 Rational<T> 內部,我們可以只寫 Rational 代替 Rational<T>。在本例中這只為我們節省了幾個字符,但是當有多個參數或有更長的參數名時,這既能節省擊鍵次數又能使最終的代碼顯得更清楚。我把這一點提前,是因為 operator* 被聲明為取得并返回 Rationals,而不是 Rational<T>s。它就像如下這樣聲明 operator* 一樣合法:

template<typename T>
class Rational {
public:
...
friend
const Rational<T> operator*(const Rational<T>& lhs,
const Rational<T>& rhs);
...
};
  然而,使用縮寫形式更簡單(而且更常用)。

  現在返回到連接問題?;旌夏J酱a編譯,因為編譯器知道我們想要調用一個特定的函數(取得一個 Rational<int> 和一個 Rational<int> 的 operator*),但是那個函數只是在 Rational 內部聲明,而沒有在此處定義。我們的意圖是讓 class 之外的 operator* template(模板)提供這個定義,但是這種方法不能工作。假如我們自己聲明一個函數(這就是我們在 Rational template(模板)內部所做的事),我們就有責任定義這個函數。當前情況是,我們沒有提供定義,這也就是連接器為什么不能找到它。

  讓它能工作的最簡單的方法或許就是將 operator* 的本體合并到它的 declaration(定義)中:

template<typename T>
class Rational {
public:
...

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"(“讓友元調用輔助函數”)的方法還是值得注重一下的。

  Rational 是一個 template(模板)的事實意味著那個 helper function(輔助函數)通常也是一個 template(模板),所以典型情況下在頭文件中定義 Rational 的代碼看起來大致如下:


template<typename T> class Rational; // declare
// Rational
// template
template<typename T> // declare
const Rational<T> doMultiply(const Rational<T>& lhs, // helper
const Rational<T>& rhs); // template
template<typename T>
class Rational {
public:
...

friend
const Rational<T> operator*(const Rational<T>& lhs,
const Rational<T>& rhs) // Have friend
{ return doMultiply(lhs, rhs); } // call helper
...
};
  多數編譯器基本上會強迫你把所有的 template definitions(模板定義)都放在頭文件中,所以你可能同樣需要在你的頭文件中定義 doMultiply。(就像 Item 30 闡述的,這樣的 templates(模板)不需要 inline(內聯)。)可能看起來就像這樣:

template<typename T> // define
const Rational<T> doMultiply(const Rational<T>& lhs, // helper
const Rational<T>& rhs) // template in
{ // header file,
return Rational<T>(lhs.numerator() * rhs.numerator(), // if necessary
lhs.denominator() * rhs.denominator());
}
  當然,作為一個 template(模板),doMultiply 不支持混合模式乘法,但是它不需要。它只被 operator* 調用,而 operator* 支持混合模式運算!本質上,函數 operator* 支持為了確保被相乘的是兩個 Rational objects 而必需的各種 type conversions(類型轉換),然后它將這兩個 objects 傳遞給一個 doMultiply template(模板)的適當的實例化來做實際的乘法。配合行動,不是嗎?

  Things to Remember

  ·在寫一個提供了 class template(類模板),而這個 class template(類模板)提供了一個函數,這個函數指涉到支持所有 parameters(參數)的 implicit type conversions(隱式類型轉換)的 template(模板)的時候,把這些函數定義為 class template(類模板)內部的 friends(友元)。
更多文章 更多內容請看C/C++技術專題專題,或

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久99精品视频一区97| 亚洲天堂精品在线| 久精品免费视频| 欧美日韩在线观看视频小说| 另类专区欧美制服同性| 久久高清视频免费| 国产噜噜噜噜久久久久久久久| 亚洲精品福利在线观看| 91久久国产综合久久91精品网站| 精品无人国产偷自产在线| 久久久999精品| 1769国内精品视频在线播放| 91亚洲国产精品| 欧美日韩国产影院| 91国产中文字幕| 亚洲自拍偷拍第一页| 欧美日韩精品在线视频| 久久久国产91| 久久久999国产精品| 亚洲qvod图片区电影| 26uuu另类亚洲欧美日本老年| 国产精品国产三级国产aⅴ浪潮| 久久久久久久91| 神马久久桃色视频| 久久久极品av| 亚洲日本欧美日韩高观看| 97国产suv精品一区二区62| 欧美激情欧美激情在线五月| 综合136福利视频在线| 91影院在线免费观看视频| 国产成人精品在线播放| 国产精品亚洲аv天堂网| 97超碰色婷婷| 中文字幕精品久久久久| 国产精品夫妻激情| 日韩中文字幕欧美| 亚洲成人a**站| 91久久嫩草影院一区二区| 色综合久久天天综线观看| 亚洲国产毛片完整版| 日韩av网站在线| 精品国产区一区二区三区在线观看| 最近2019年中文视频免费在线观看| 国产国产精品人在线视| 欧美激情高清视频| 色综合老司机第九色激情| 久久99热精品| 韩国国内大量揄拍精品视频| 久久伊人色综合| 成人性生交大片免费观看嘿嘿视频| 日韩中文字幕视频| 久久精品成人动漫| 国产精品专区h在线观看| 欧美电影免费在线观看| 亚洲最大的免费| 欧美色另类天堂2015| 亚洲免费视频观看| 91色视频在线观看| 久久成人免费视频| 久久久99久久精品女同性| 亚洲精品自拍视频| 91沈先生在线观看| 国产精品美女视频网站| 久久999免费视频| 成人精品网站在线观看| 国产日韩欧美夫妻视频在线观看| 日韩欧美黄色动漫| 国产一区私人高清影院| 91视频九色网站| 日本一区二区三区在线播放| 色哟哟亚洲精品一区二区| 综合欧美国产视频二区| 日本乱人伦a精品| 欧美日韩黄色大片| 亚洲xxxxx| 日本高清视频精品| 亚洲欧美国产另类| www.日韩不卡电影av| 蜜月aⅴ免费一区二区三区| 精品日本美女福利在线观看| 欧美极品欧美精品欧美视频| 91视频-88av| 久久免费国产视频| 欧美激情图片区| 国产精品伦子伦免费视频| 在线色欧美三级视频| 一本色道久久88精品综合| 91沈先生作品| 狠狠综合久久av一区二区小说| 精品女同一区二区三区在线播放| 在线观看亚洲视频| 成人精品久久av网站| 亚洲aa中文字幕| 国产精品专区一| 国产激情久久久久| 中日韩美女免费视频网址在线观看| 日韩在线观看免费全| 亚洲国产精品免费| 日韩视频免费在线观看| 在线观看欧美视频| 亚洲欧洲自拍偷拍| 精品夜色国产国偷在线| 午夜精品久久久久久久久久久久| 亚洲午夜性刺激影院| 性色av一区二区三区| 一区二区亚洲欧洲国产日韩| 欧美精品亚州精品| 一区二区三区视频免费在线观看| 亚洲自拍偷拍一区| 日本中文字幕不卡免费| 欲色天天网综合久久| 久久香蕉精品香蕉| 国产日韩精品电影| 久久精品国产亚洲精品2020| 成人日韩在线电影| 国内精品一区二区三区四区| 高清欧美性猛交xxxx黑人猛交| 亚洲白拍色综合图区| 精品夜色国产国偷在线| 成人伊人精品色xxxx视频| 欧美—级高清免费播放| 国产综合在线看| 亚洲人高潮女人毛茸茸| 国产精品老女人视频| 欧美日在线观看| 国产亚洲精品久久| 在线视频日本亚洲性| 日本中文字幕不卡免费| 亚洲第一中文字幕在线观看| 精品少妇v888av| 亚洲天堂男人天堂| 日韩精品极品在线观看| 亚洲精品久久视频| 欧美激情啊啊啊| 亚洲在线观看视频网站| 国产视频亚洲精品| 久久精品中文字幕电影| 92国产精品久久久久首页| 欧美午夜无遮挡| 久久99精品久久久久久青青91| 久久欧美在线电影| 国产午夜精品视频| 国产精品久久91| 成人春色激情网| 国产精品一区二区3区| 91久久久精品| 精品久久国产精品| 91丝袜美腿美女视频网站| 亚洲国产精品一区二区三区| 日韩成人av在线播放| 国产精品第一视频| 91极品视频在线| 在线一区二区日韩| 日韩高清电影免费观看完整| 欧美日韩精品在线| 欧美国产日韩视频| 亚洲香蕉成视频在线观看| 伊人成人开心激情综合网| 一个色综合导航| 97久久久免费福利网址| 亚洲国产精品嫩草影院久久| 亚洲精品黄网在线观看| 操日韩av在线电影| 亚洲福利在线视频|