運算符重載詳解(五)

9.轉換構造函數進行不同類型數據的轉換
轉換構造函數的作用是將一個其他類型的數據轉換成一個類的對象。
轉換構造函數也是一種構造函數,它遵循構造函數的一般規律,通常把有一個參數的構造函數用作類型轉換,所以,稱爲轉換構造函數。
注意:轉換構造函數只能有一個參數,如果有多個參數的,它就不是轉換構造函數,原因很簡單:如果有多個參數的話,究竟是把那個參數轉換成Complex類的對象呢?

使用轉換構造函數將一個指定的數據轉換爲類對象的方法如下:
<1>先聲明一個類
<2>在這個類中定義一個只有一個參數的構造函數,參數的類型是需要轉換的類型,在函數體中指定轉換的方法。
<3>在該類的作用域內可以用以下形式進行類型轉換:
類名(指定類型的數據)
就可以將指定類型的數據轉化爲此類的對象。
不僅可以將一個標準類型數據轉換成類對象,也可以將另一個類的對象轉換成轉換構造函數躲在的類對象。如將一個學生類對象轉換爲教師類對象。如
Teacher(Student& s){num =s.num;strcpy(name,s.name);}
但是,對象s中的num,name必須是公有成員,否則不能被類外引用。

以前學過的構造函數有:
默認構造函數:如Complex();//沒有參數
用於初始化的構造函數:如Complex(double r, double i);
用於複製對象的複製構造函數:如Complex(Complex& c);//形參是本類對象的引用
轉換構造函數只有一個參數,如:

Complex(double r){ real = r, imag = 0; }

其作用是將double型的參數r轉換成Complex類的對象,將r作爲複數的實部,虛部爲0。
上述構造函數可以同時出現在同一個類中,他們都是構造函數的重載。編譯系統會根據建立對象時給出的實參的個數與類型選擇形參與之匹配的構造函數。
例子:

Complex c1(3.5); //將double型常數轉換成一個名爲c1的Complex類對象
Complex c1;  //建立無名的對象
c1 = Complex(3.5);

若已對運算符+進行了重載,使之能進行兩個Complex類對象的相加,若有以下表達式

c3 = c1 + 2.5;   //編譯出錯

編譯出錯,不能用運算符+將一個Complex類對象和一個浮點數相加,可以先將2.5轉換爲Complex類無名對象,然後相加

c3 = c1 + Complex(2.5); //合法

10.類型轉換函數
類型轉化函數的作用是將一個類的對象轉換成另一類型的數據。類型轉換函數的一般形式:
operator 類型名()
{實現轉換的語句}
注:在函數名前面不能指定函數類型,函數沒有參數。返回值類型是由函數名中指定的類型名來確定的
類型轉換函數只能作爲成員函數,因爲轉換的主體是本類的對象,不能作爲友元函數或普通函數。

例子:
如已聲明瞭一個Complex類,定義類型轉換函數如下:

operator double()  //operator double是函數名
{ return real;}

函數返回值是double型變量real的值,作用是將一個Complex類對象轉換爲一個double型數據,其值是Complex類中的數據成員real的值。
<1>已經定義d1,d2爲double型變量,c1,c2爲Complex類對象,類中已經定義了類型轉換函數,如下表達式:

d1 = d2 + c1; //類型轉換函數將c1轉換爲double

編譯器發現“+”的左側d2是double型,而右側的c1是Complex類對象,如果沒有對運算符“+”進行重載,就會檢查有無類型轉換函數,若有對double的重載函數,就把Complex類對象c1轉換爲double型數據,建立一個臨時的double數據,並與d2相加。
<2>若類中已定義了轉換構造函數並且又重載了運算符“+”(作爲Complex類的友元函數),但未對double定義類型轉換函數(或者說未對double重載),以下表達式

c2 = c1 + d2; //

該怎麼處理?
運算符“+”左側的c1是Complex類對象,右側d2是double型,編譯系統尋找有無對“+”的重載,發現有operator + 函數,但是它是Complex類的友元函數,要求兩個Complex類的形參,而現在d2是double,不符合要求,類中有沒有對double進行重載,因此不可能把c1轉換爲double然後相加,編譯系統就去找有無轉換構造函數,發現有,就調用轉換構造函數Complex(d2),建立一個臨時的Complex類對象,再調用operator + 函數,將兩個複數相加,相當於表達式:

c2 = c1 + Complex(d2);

<3>若已對運算符“+”重載,使兩個Complex類對象相加,則以下表達式

d1 = c1 + c2;

將c1和c2兩個類對象相加,得到一個臨時的Complex類對象,由於它不能賦值給double型變量,而又有對double的重載函數,於是把臨時對象轉換爲double數據,然後賦值給d。
例子:

class Complex
{
public:
	Complex(){ real = 0, imag = 0; } //定義構造函數
	Complex(double r, double i){ real = r, imag = i; }//構造函數重載
	operator double(){ return real; } //定義類型轉換函數
private:
	double real;	//實部
	double imag;	//虛部
};
int main()
{
	Complex c1(3, 4), c2(5, -10), c3;
	double d;
	d = 2.5 + c1; //調用operator double類型轉換函數,將Complex類對象隱式轉換爲double型數據
	cout << d;  //5.5
	return 0;
}

問題:使用類型轉換函數有什麼好處?
假如程序中需要對一個Complex類對象和一個double型變量進行+ - * /等算術運算以及關係運算和邏輯運算,如果不用類型轉換函數,就要對多種運算符進行重載,以便能進行各種運算,這樣是十分麻煩的,工作量較大,程序顯得冗長。如果使用類型轉換函數對double進行重載(使Complex類對象轉換爲double型數據),就不必對各種運算符進行重載,因爲Complex類對象可以被自動地轉換爲double型數據,而標準類型的數據的運算,是可以使用系統提供的各種運算符的。

例子:

class Complex
{
public:
	Complex(){ real = 0, imag = 0; } //定義構造函數
	Complex(double r, double i){ real = r, imag = i; }//構造函數重載,函數初始化
	Complex(double r){ real = r, imag = 0; }//轉換構造函數
	friend Complex operator + (Complex c1, Complex c2); //類型轉換函數,一個形參
	void display();
private:
	double real;	//實部
	double imag;	//虛部
};
Complex operator + (Complex c1, Complex c2)//定義運算符+的重載函數
{	return Complex(c1.real + c2.real, c1.imag + c2.imag);}
void Complex::display()
{   cout << real << "+" << imag << "i";}
int main()
{
	Complex c1(3, 4), c2(5, -10), c3;
	c3 = c1 + 2.5;//operator + (c1,Complex(2.5))
	c3.display();
	return 0;
}

c3 = c1 + 2.5;//operator + (c1,Complex(2.5))改爲c3 = 2.5 + c1;//operator + (Complex(2.5), c1)也是可以的。
重要結論
在已定義了相應的轉換構造函數情況下,將運算符“+”函數重載爲友元函數,在進行兩個複數相加時,可以用交換律。

問題:能否將運算符“+”重載函數作爲Complex類的成員函數得到上述結果呢?
作爲Complex類的成員函數是不行的。
成員函數原型:operator + (Complex c2);函數的第一個參數省略了,它隱指this所指的對象,如果表達式爲:c1+2.5,編譯系統解釋爲c1.operator + (Complex (2.5));如果表達式爲:2.5+c1,編譯系統解釋爲(2.5).operator+(c1)顯然是錯誤的,無法實現的。

結論:如果運算符函數重載爲成員函數,它的第1個參數必須是本類的對象,。當第1個操作數不是類對象時,不能將運算符函數重載爲成員函數。如果將運算符“+”函數重載爲類的成員函數,交換律不適應。
由於這個原因,一般情況下將雙目運算符函數重載爲友元函數。單目運算符則多重載爲成員函數。
如果一定要將運算符函數重載爲成員函數,而第1個操作數又不是類對象時,只有一個辦法能夠解決,再重載一個運算符“+”函數,其第一個參數爲doule型,當然此函數只能是友元函數,函數原型爲:friend Complex operator + (double, Complex);顯然是不太方便,還是重載爲友元函數方便些。

問題:若此時類中包含轉換構造函數、運算符“+”重載函數、類型轉換函數,請分析他們之間的關係,如何執行,有無矛盾?

Complex(){ real = 0, imag = 0; } //定義構造函數
Complex(double r, double i){ real = r, imag = i; }//構造函數重載,函數初始化
Complex(double r){ real = r, imag = 0; }//轉換構造函數
operator double(){ return real; } //類型轉換函數,無參數
friend Complex operator + (Complex c1, Complex c2); //類型轉換函數,一個形參

下面表達式該如何執行

c3 = c1 + 2.5;

程序在編譯時出錯,原因是在處理c1 + 2.5時出現二義性。
一種理解爲調用轉換構造函數,把2.5變成Complex類對象,然後調用運算符“+”重載函數,與c1進行復數相加。
另一種理解是,調用類型轉換函數,把c1轉換爲double型數,然後與2.5進行相加。
系統無法判定,這二者是矛盾的。
如果要使用類型轉換函數,就應當刪去運算符“+”重載函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章