1. 程式人生 > 實用技巧 >a review at operator overloading

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

這兩行程式碼源於標準庫,看似簡單,實際很複雜

  1. 為何用inline? 因為當函式短小且不斷被多次呼叫的時候會消耗掉大量的stack,所以要用inline,讓編譯器把這個函式展開
  2. 為什麼+=內部要設計為呼叫__doapl(this, r)? 不知道,設計問題,照著做就行了,就是要疊一層
  3. 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