需要型別轉換時定義為非成員函式

2021-08-28 08:32:08 字數 1994 閱讀 5145

所以為了看我文章的人不會遭遇同樣的問題,

2.盡可能循序漸進(還是看不懂可能是我沒有這樣的天賦),標出閱讀的前提知識

3.列出的**自己先跑一遍

c++1.類

2.函式過載

3.型別轉換

整合開發環境:visual studio 2017

class num

//不設explicit,提供隱式轉換

constnum operator*(const num& rhs)const

const int getn()const

const int getm()const

private:

int n;

int m;

};int main()

為何num3=num3* 2成功而num3=2* num1卻失敗

因為num3=num3*2中,函式operator=由num3呼叫且引數為2,引數2為int可通過建構函式隱式轉換為num,所以成功

而num3=num3*2中,雖然想呼叫operator=但,這個函式卻不屬於int,這個基礎型別int根本不擁有函式。

使用函式形式重寫上面兩個例子:

num3=num3.operator*(2);

num3=2.operator*(num3); //明顯錯誤

上述情況下,編譯器會嘗試尋找引數為(int,num)的operator*的非成員函式。

所以只要寫乙個引數為(int,num)的operator的非成員函式即可,這就是我們一般過載乘法運算子時的做法————將過載乘法運算子宣告為friend函式,即非成員函式的operator可以呼叫類中的private成員進行運算。

friend const num operator*(const num& lhs,const num& rhs)const

因為宣告為友元函式,不再是成員函式,成員函式隱含乙個引數this指向呼叫方,所以友元函式比成員函式多乙個引數。

num3=2*num1;               //成功

<=>num3=operator*(num(2),num1);

該條款的重點在於,只有引數位於引數列中,這個引數才有可能被隱式型別轉換。

條款24的公升級版?可能這樣說有點不妥,實質上就是把條跨23中的類模板化了,但是一旦模板化了事情就會變得複雜,因為編譯器的處理策略不同了。

template

class num

constt getn()const

constt getm()const

private:

tn;tm;

};num num;

num=num2; //失敗

上面這個例子跟條款24一致,但是卻失敗了,因為編譯器並不清楚我們要使用哪乙個函式,我們想要使用operator(num,num)函式,但是編譯器必須知道t的型別才能具體化出這個函式,但是它不知道。

在第一引數num時編譯器可以推導出t為int,而在第二引數2,它是個int,那麼編譯器從這個int中就推不出t究竟是個啥。在我們的預想中,我們期望編譯器能夠把int隱式轉換為num,但是編譯器不會這麼做,因為推導模板實參時並不考慮通過建構函式產生的隱式轉換。

那麼怎麼辦呢,這裡有個有趣的辦法,模板類中友元宣告可以指定特定函式,也就是說只要類被具體化,這個函式就會被同時具體化,就不用在依賴實參推導來具體化函式。即是模板類友元函式,不再是個函式模板而是個模板函式。(前者只是個模具無法直接使用,而後者已經具體化可以直接使用)

雖然上述可以通過編譯器,但是卻無法鏈結因為我們沒有實現它,我們在類中宣告了這個友元函式,期待在類外實現它,但是不行因為這個宣告是num內的所作所為,我們無法在類外實現他,因為我們不能提前指定t並讓聯結器連線到它,那麼就必須在num中實現它,在宣告式中實現它,讓它成為乙個內聯函式。

我們並不使用友元可以訪問類中私有成員的特性,而是利用其指定特定函式。

轉送(也是我)

C 需要型別轉換時請為模板定義非成員函式

20180403 c 需要型別轉換時請為模板定義非成員函式 只有非成員函式才有能力 在所有實參身上實施隱式型別轉換 該條款可以通過rational 有理數 類和operator 函式為例證明。本文將擴充這一條款 將rational類和operator 函式模板化 template class rat...

條款46 需要型別轉換時請為模板定義非成員函式

條款46 需要型別轉換時請為模板定義非成員函式 define non member functions inside templates when type conversion are desired.還記得在條款24中,我們提到只有non member函式才有能力 在所有實參身上實施隱式型別轉換...

將過載運算子定義為成員函式還是普通的非成員函式

賦值 下標 呼叫 和成員訪問箭頭 必須是成員函式 復合賦值運算子應該是成員,但是並非必須 改變物件狀態的運算子或者與給定型別密切相關的運算子,如 遞增 遞減和解引用運算子應該 是成員 具有對稱性的運算子可能轉換任一端的運算物件,例如算數 相等性 關係和位運算子等,因此通常應該是普通的非成員函式。舉例...