C++基礎--complex(複數)類的設計過程與思考總結
專案
1.設計complex(複數類)
需求:1)實部,虛部re,im
2)重寫+=符號,呼叫friend_doapl函式,對兩個複數進行相加 其中+=函式呼叫一個全域性函式_doapl(complex*,complext&)進行處理。這裡只用完成兩個複數的相加
3)重寫+符號,這裡只用完成兩個複數,複數和實數的相加
設計完成後的程式碼
#ifndef __MYCOMPLEX__ #define __MYCOMPLEX__ class complex; complex& __doapl(complex* ths, const complex& r); complex& __doami(complex* ths, const complex& r); complex& __doaml(complex* ths, const complex& r); class complex { public: complex(double r = 0, double i = 0) : re(r), im(i) { } complex& operator += (const complex&); double real() const { return re; } double imag() const { return im; } private: double re, im; friend complex& __doapl(complex*, const complex&); }; inline complex& __doapl(complex* ths, const complex& r) { ths->re += r.re; ths->im += r.im; return *ths; } inline complex& complex::operator += (const complex& r) { return __doapl(this, r); } inline double imag(const complex& x) { return x.imag(); } inline double real(const complex& x) { return x.real(); } inline complex operator + (const complex& x, const complex& y) { return complex(real(x) + real(y), imag(x) + imag(y)); } inline complex operator + (const complex& x, double y) { return complex(real(x) + y, imag(x)); } inline complex operator + (double x, const complex& y) { return complex(x + real(y), imag(y)); }
endif //MYCOMPLEX
設計:
1)確定成員變數以及get方法 思考函式const,real()和img需要加,因為不需要修改值。
2)確定過載符號operator +=方法。
complex& operator +=(const complex&);
思考返回值是什麼型別。我們在複數類計算時,經常 x+=y,等價於x = x+y. 因此,確定返回的是原來的x的值,也就是this。我們可以得出,直接傳回引用,因為我們傳回去得並不是local variable。但為什麼我們不設計是void型別呢?因為當我們計算x+=y的時候,我們可以直接通過引用改變x的值呀?
就比如:
complex& operator +=(const complex& c){
this.re = this.re+c.real();
}
原因就在於,在c++中可以連續複製,如 x1+=x2+=x3; 當發生這種情況的時候,引用必須返回以供作為右值以供下一次的運算。
思考形式引數。能用引用得就用引用。且原值能不能修改呢? x = x+y this指的是x的資料,形式引數指的是y的資料。x的資料發生了改變,但是y的沒有。所以我們得出,形式引數要加上const。
3)全域性函式_doapl(complex&,complext&)
可能是因為其他地方也要用到,所以就把它寫成了全域性函式而不是成員函式。為了實現 operator+=呼叫它,我們得將它宣告為一個友元。
其成員變數兩個一個是complex*而非complex&的原因是,要傳入this,與operator+=發生聯動。
4)設計 operator+過載
思考返回值型別,假設有 x3 = x1+x2。x3必然是在函式內新建一個變數並返回,所以不能返回一個區域性變數的引用。只能使用值傳遞。
此外,我們可以注意到,operator+定義在了類外,因為它不需要this這個變數,且operator+二目運算子只允許有兩個引數,要想不加入this(類內函式預設新增this形式引數),只能寫在類外作為成員函式。
那還有幾個問題,複數相加有很多種可能,以下是應該考慮的可能性,我們必須根據這些可能性設計函式的過載:
/**
有三種情況
1.複數加複數
2.複數+double
3.double+複數
**/
inline complex
operator + (const complex& x, const complex& y)
{
return complex (real (x) + real (y), imag (x) + imag (y));
}
inline complex
operator + (const complex& x, double y)
{
return complex (real (x) + y, imag (x));
}
inline complex
operator + (double x, const complex& y)
{
return complex (x + real (y), imag (y));
}
從complex得到的經驗
1)若方法不需要修改資料,一定加上const,因為const物件只能呼叫const方法。若方法不加const,const物件功能不全。
- 形式引數都應該傳遞引用,如果不需要修改,則一定加上const,否則原值可能被修改。若直接傳遞了值,則發生複製,會很慢。當然,char這種一個位元組的引數可以傳值。
3)返回值也儘量用引用傳遞,快。但是一定不能返回區域性變數的引用,因為區域性變數存在棧中,方法執行完之後記憶體就被回收了。
4)簡單的函式要加inline即使編譯器會自動選擇。
5).h檔案的劃分
其中,類聲明裡的函式不用寫具體的形式引數,只用寫形式引數的型別即可。簡單的函式可以在類宣告部分就定義如 real()和Img()。複雜的應該在函式體外進行定義。最後,類內的函式均會自動加上inline,在類外定義的函式若比較簡單,應該手動建議編譯器使用inlien.
6)操作符過載時,若是雙目運算子 如 + 則應該定義為全域性函式。
如z = x+y。使用+號時,不需要this的值。
與之相對的是單目運算子,如==或+=
如判斷 z==y 的時候,我們需要用到z的值,所以必須定義在類內,所以就沒有意義了
7)在函式宣告階段,複雜的函式不用寫函式體,也不用寫具體的形式引數,只用寫形式引數的型別。
如:
complex&
operator +=(const complex&); //不需要寫成(const complex&r)
,只寫函式名。
但簡單的如real()可以寫完函式體。複雜的函式應該在類定義區域完成函式體的編寫。