1. 程式人生 > 實用技巧 >C++基礎--complex(複數)類的設計過程與思考總結

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物件功能不全。

  1. 形式引數都應該傳遞引用,如果不需要修改,則一定加上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()可以寫完函式體。複雜的函式應該在類定義區域完成函式體的編寫。