a review at operator overloading
定義一個complex類
complex c1 (5, 1);
complex c2 (2);
c2 += c1;
c2 += c1 += c1;
由於我們沒有對complex類定義+=操作符,所以這一行會報錯。
於是乎我們定義complex類+=的operator overloading
inline complex& complex::operator += (const complex& r) { return __doapl(this, r); } inline complex& __doapl(complex* ths, const complex& r) { ths->re += r.re; ths->im += r.im; return *ths; }
這兩行程式碼源於標準庫,看似簡單,實際很複雜
- 為何用inline? 因為當函式短小且不斷被多次呼叫的時候會消耗掉大量的stack,所以要用inline,讓編譯器把這個函式展開
- 為什麼+=內部要設計為呼叫__doapl(this, r)? 不知道,設計問題,照著做就行了,就是要疊一層
- c2 += c1的具體呼叫順序是如何?
- 首先編譯器讀入c2 += c1,識別出+=是一個二元運算子(注意:不是編譯器真的預先知道+=代表了二元,而是它找到了c2是左值,+=在中間,c1是右值,所以認定+=是二元操作符),之後去尋找程式中是否有"complex& aaaaaa" "+=" "complex bbbbbb"這樣結構的定義
- 於是接著上文,這兩段程式難以理解的地方還有一個this的問題,因為我們這個是包裝在complex內的function,假設有不是包裝在complex內的function,比如普通加法
inline complex operator+(const complex& x, const complex& y) {
return complex(real(x) + real(y), image(x) + image(y));
}
complex c1, c2, c3;
c2 = c1 + c2;
-
這裡產生了個疑惑,為什麼同為二元運算子,同為加法,這個函式卻有x, y兩個引數,而
inline complex& complex::operator += (const complex& r)
- 這涉及到this指標的問題
-
對於
inline complex& complex::operator += (const complex& r)
函式,編譯器會將它認為是inline complex& complex::operator += (this, const complex & r)
因為它是類的成員函式,所以多了一個this,代表這個類的例項本身,所以c2 += c1
,本質上還是兩個引數,為什麼只寫一個引數?因為剩下的那個(隱藏的)引數代表自身。 -
對於上述的+號,執行流程為,識別二元操作符+,去找
-
那麼:c1+=c2+=c1如何理解呢???
- 因為它的實現是返回一個complex&,假設返回一個void,c2+=c1是可以執行的,但是c2+=c1這個返回值是void,再加到c1就不行了。那麼,為什麼返回一個complex&而不是complex呢?因為快
-
問題來了,那為什麼
inline complex operator+(const complex& x, const complex& y)
不return引用呢?這樣不也是快麼??因為+=後的返回值,是下一次+=的引數,+=到最後,它的最後返回值同樣會賦值一個上文已存的complex,這是合法的。inline complex& operator+(const complex& x, const complex& y)
不合法,是因為它返回的complex在函式生命週期銷燬後,就不具備&了。 -
有一個例外
inline complex& operator+ (const complex& x) {
return x;
}
這裡標準庫沒寫&,但實際上寫了也沒事,因為x的生命週期是上文給的
但是對於-號這麼寫就是錯的,如下:
inline complex& operator- (const complex& x) {
return complex(-real(x), -image(x));
}
- 還有一個問題:
inline complex conj(const complex &x ) {
return complex(real(x), -image(x));
}
cout << conj(c1) << endl;
cout << conj(c1) << conj(c2) << endl;
如何過載<<
? 答案是這樣的
#include <iostream>
ostream& operator << (ostream& os, complex& c1) {
return os << "image" << c1.image << "real" << c1.real;
}
- 首先這個無法寫成類函式,因為cout是一個ostream物件,標準庫寫好的,我們只能寫成global,然後,按照ostream << complex的結構,我們將第一個引數定義為ostream& os, &為了效率,不能加const注意,因為加了const我們就沒有辦法寫入這個ostream了,然後complex& c1。。。。對於連續輸出<<,就是一個執行順序的問題,從左到右,返回ostream&,(不存在ostream&物件在函式內銷燬的問題,所以沒必要輸出ostream)不贅述。
operator overload知識點太雜,這篇部落格還是介紹的蠻全的 https://www.cnblogs.com/linuxAndMcu/p/10395383.html