用轉換構造函數可以將一個指定類型的數據轉換為類的對象。但是不能反過來將一個類的對象轉換為一個其他類型的數據(例如將一個Complex類對象轉換成double類型數據)。
C++提供類型轉換函數(type conversion function)來解決這個問題。類型轉換函數的作用是將一個類的對象轉換成另一類型的數據。如果已聲明了一個Complex類,可以在Complex類中這樣定義類型轉換函數:
operator double( )
{
return real;
}
函數返回double型變量real的值。它的作用是將一個Complex類對象轉換為一個double型數據,其值是Complex類中的數據成員real的值。請注意,函數名是operator double,這點是和運算符重載時的規律一致的(在定義運算符“+”的重載函數時,函數名是operator +)。
類型轉換函數的一般形式為:
operator 類型名( )
{
實現轉換的語句
}
在函數名前面不能指定函數類型,函數沒有參數。其返回值的類型是由函數名中指定的類型名來確定的。類型轉換函數只能作為成員函數,因為轉換的主體是本類的對象。不能作為友元函數或普通函數。
從函數形式可以看到,它與運算符重載函數相似,都是用關鍵字operator開頭,只是被重載的是類型名。double類型經過重載后,除了原有的含義外,還獲得新的含義(將一個Complex類對象轉換為double類型數據,並指定了轉換方法)。這樣,編譯系統不僅能識別原有的double型數據,而且還會把Complex類對象作為double型數據處理。
那么程序中的Complex類對具有雙重身份,既是Complex類對象,又可作為double類型數據。Complex類對象只有在需要時才進行轉換,要根據表達式的上下文來決定。轉換構造函數和類型轉換運算符有一個共同的功能:當需要的時候,編譯系統會自動調用這些函數,建立一個無名的臨時對象(或臨時變量)。
[例10.9] 使用類型轉換函數的簡單例子。
- #include <iostream>
- using namespace std;
- 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;//要求將一個double數據與Complex類數據相加
- cout<<d<<endl;
- return 0;
- }
對程序的分析:
1) 如果在Complex類中沒有定義類型轉換函數operator double,程序編譯將出錯。因為不能實現double 型數據與Complex類對象的相加。現在,已定義了成員函數 operator double,就可以利用它將Complex類對象轉換為double型數據。請注意,程序中不必顯式地調用類型轉換函數,它是自動被調用的,即隱式調用。在什么情況下調用類型轉換函數呢?編譯系統在處理表達式 2.5 +cl 時,發現運算符“+”的左側是double型數據,而右側是Complex類對象,又無運算符“+”重載函數,不能直接相加,編譯系統發現有對double的重載函數,因此調用這個函數,返回一個double型數據,然后與2.5相加。
2) 如果在main函數中加一個語句:
c3=c2;
請問此時編譯系統是把c2按Complex類對象處理呢,還是按double型數據處理?由於賦值號兩側都是同一類的數據,是可以合法進行賦值的,沒有必要把c2轉換為double型數據。
3) 如果在Complex類中聲明了重載運算符“+”函數作為友元函數:
Complex operator+ (Complex c1,Complex c2)//定義運算符“+”重載函數
{
return Complex(c1.real+c2.real, c1.imag+c2.imag);
}
若在main函數中有語句
c3=c1+c2;
由於已對運算符“+”重載,使之能用於兩個Complex類對象的相加,因此將c1和c2按Complex類對象處理,相加后賦值給同類對象c3。如果改為
d=c1+c2; //d為double型變量
將c1與c2兩個類對象相加,得到一個臨時的Complex類對象,由於它不能賦值給double型變量,而又有對double的重載函數,於是調用此函數,把臨時類對象轉換為double數據,然后賦給d。
從前面的介紹可知,對類型的重載和對運算符的重載的概念和方法都是相似的,重載函數都使用關鍵字operator。因此,通常把類型轉換函數也稱為類型轉換運算符函數,由於它也是重載函數,因此也稱為類型轉換運算符重載函數(或稱強制類型轉換運算符重載函數)。
假如程序中需要對一個Complex類對象和一個double型變量進行+,-,*,/等算術運算,以及關系運算和邏輯運算,如果不用類型轉換函數,就要對多種運算符進行重載,以便能進行各種運算。這樣,是十分麻煩的,工作量較大,程序顯得冗長。如果用類型轉換函數對double進行重載(使Complex類對象轉換為double型數據),就不必對各種運算符進行重載,因為Complex類對象可以被自動地轉換為double型數據,而標准類型的數據的運算,是可以使用系統提供的各種運算符的。
[例10.10] 包含轉換構造函數、運算符重載函數和類型轉換函數的程序。先閱讀以下程序,在這個程序中只包含轉換構造函數和運算符重載函數。
- #include <iostream>
- using namespace std;
- class Complex
- {
- public:
- Complex( ){real=0;imag=0;} //默認構造函數
- Complex(double r){real=r;imag=0;}//轉換構造函數
- Complex(double r,double i){real=r;imag=i;}//實現初始化的構造函數
- 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)"<<endl;
- }
- int main( )
- {
- Complex c1(3,4),c2(5,-10),c3;
- c3=c1+2.5; //復數與double數據相加
- c3.display( );
- return 0;
- }
注意,在Visual C++ 6.0環境下運行時,需將第一行改為#include <iostream.h>,並刪去第2行,否則編譯不能通過。
對程序的分析:
1) 如果沒有定義轉換構造函數,則此程序編譯出錯。
2) 現在,在類Complex中定義了轉換構造函數,並具體規定了怎樣構成一個復數。由於已重載了算符“+”,在處理表達式c1+2.5時,編譯系統把它解釋為
operator+(c1, 2.5)
由於2.5不是Complex類對象,系統先調用轉換構造函數Complex(2.5),建立一個臨時的Complex類對象,其值為(2.5+0i)。上面的函數調用相當於
operator+(c1, Complex(2.5))
將c1與(2.5+0i) 相加,賦給c3。運行結果為
(5.5+4i)
3) 如果把“c3=c1+2.5;”改為c3=2.5+c1; 程序可以通過編譯和正常運行。過程與前相同。
從中得到一個重要結論,在已定義了相應的轉換構造函數情況下,將運算符“+”函數重載為友元函數,在進行兩個復數相加時,可以用交換律。
如果運算符函數重載為成員函數,它的第一個參數必須是本類的對象。當第一個操作數不是類對象時,不能將運算符函數重載為成員函數。如果將運算符“+”函數重載為類的成員函數,交換律不適用。
由於這個原因,一般情況下將雙目運算符函數重載為友元函數。單目運算符則多重載為成員函數。
4) 如果一定要將運算符函數重載為成員函數,而第一個操作數又不是類對象時,只有一個辦法能夠解決,再重載一個運算符“+”函數,其第一個參數為double型。當然此函數只能是友元函數,函數原型為
friend operator+(double, Complex &);
顯然這樣做不太方便,還是將雙目運算符函數重載為友元函數方便些。
5) 在上面程序的基礎上增加類型轉換函數:
operator double( ){return real;}
此時Complex類的公用部分為:
public:
Complex( ){real=0;imag=0;}
Complex(double r){real=r;imag=0;} //轉換構造函數
Complex(double r,double i){real=r;imag=i;}
operator double( ){return real;}//類型轉換函數
friend Complex operator+ (Complex c1,Complex c2); //重載運算符“+”
void display( );
其余部分不變。程序在編譯時出錯,原因是出現二義性。