技術(shù)交流QQ群:1027579432,歡迎你的加入!
1.C++轉(zhuǎn)換構(gòu)造函數(shù):將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)的類(lèi)型
- 在C/C++中,不同的數(shù)據(jù)類(lèi)型之間可以相互轉(zhuǎn)換。無(wú)需用戶(hù)指明如何轉(zhuǎn)換的稱(chēng)為自動(dòng)類(lèi)型轉(zhuǎn)換(隱式類(lèi)型轉(zhuǎn)換),需要用戶(hù)顯式地指明如何轉(zhuǎn)換的稱(chēng)為強(qiáng)制類(lèi)型轉(zhuǎn)換。
// 自動(dòng)類(lèi)型轉(zhuǎn)換示例 int a = 6; a = a + 3.12; // 將小數(shù)轉(zhuǎn)換為整數(shù)會(huì)抹掉小數(shù)點(diǎn)后面的數(shù)字 // 強(qiáng)制類(lèi)型轉(zhuǎn)換示例 int b = 100; int *p = &b; float *ptr = (float *)p; // 將int *轉(zhuǎn)換為float *只是簡(jiǎn)單地復(fù)制指針的值 -
不管是自動(dòng)類(lèi)型轉(zhuǎn)換還是強(qiáng)制類(lèi)型轉(zhuǎn)換,前提必須是編譯器知道如何轉(zhuǎn)換,例如,將小數(shù)轉(zhuǎn)換為整數(shù)會(huì)抹掉小數(shù)點(diǎn)后面的數(shù)字,將int *轉(zhuǎn)換為float *只是簡(jiǎn)單地復(fù)制指針的值,這些規(guī)則都是編譯器內(nèi)置的,我們并沒(méi)有告訴編譯器??傊?,如果編譯器不知道轉(zhuǎn)換規(guī)則就不能轉(zhuǎn)換,使用強(qiáng)制類(lèi)型也無(wú)用,請(qǐng)看下面的例子:
#include "iostream" using namespace std; // 如果編譯器不知道轉(zhuǎn)換規(guī)則就不能轉(zhuǎn)換,使用強(qiáng)制類(lèi)型也無(wú)用 class complex{ public: complex():m_real(0.0), m_img(0.0){} complex(double real, double img):m_real(real), m_img(img){} public: friend ostream & operator<< (ostream &out, const complex &c); // 友元函數(shù) private: double m_real; double m_img; }; ostream & operator << (ostream &out, const complex &c){ out << c.m_real << "+" << c.m_img << "i"; return out; } int main(){ complex a(10.0, 20.0); a = (complex) 25.5; // 錯(cuò)誤,轉(zhuǎn)換失敗 return 0; } - 上面的例子中,25.5是實(shí)數(shù),a是復(fù)數(shù),將25.5賦值給a后,我們期望a的實(shí)部變?yōu)?5.5,而虛部為0。但是,編譯器并不知道這個(gè)轉(zhuǎn)換規(guī)則,這超出了編譯器的處理能力,所以轉(zhuǎn)換失敗,即使加上強(qiáng)制類(lèi)型轉(zhuǎn)換也無(wú)用。幸運(yùn)的是,C++允許我們自定義類(lèi)型轉(zhuǎn)換規(guī)則,用戶(hù)可以將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)類(lèi)型,也可以將當(dāng)前類(lèi)類(lèi)型轉(zhuǎn)換為其它類(lèi)型。這種自定義的類(lèi)型轉(zhuǎn)換規(guī)則只能以類(lèi)的成員函數(shù)的形式出現(xiàn)。換句話說(shuō),這種轉(zhuǎn)換規(guī)則只適用于類(lèi),本節(jié)先講解如何將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)類(lèi)型。
2.轉(zhuǎn)換構(gòu)造函數(shù)
-
將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)類(lèi)型需要借助轉(zhuǎn)換構(gòu)造函數(shù)(Conversion constructor)。轉(zhuǎn)換構(gòu)造函數(shù)也是一種構(gòu)造函數(shù),它遵循構(gòu)造函數(shù)的一般規(guī)則,轉(zhuǎn)換構(gòu)造函數(shù)只有一個(gè)參數(shù)。
#include "iostream" using namespace std; /*---------------------------將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)的類(lèi)型-------------------------------*/ // 如果編譯器不知道轉(zhuǎn)換規(guī)則就不能轉(zhuǎn)換,使用強(qiáng)制類(lèi)型也無(wú)用 class complex{ public: complex():m_real(0.0), m_img(0.0){} complex(double real, double img):m_real(real), m_img(img){} complex(double real): m_real(real), m_img(0.0){} // 轉(zhuǎn)換構(gòu)造函數(shù),作用是將double類(lèi)型的參數(shù)real轉(zhuǎn)換成 complex類(lèi)的對(duì)象,并將real作為復(fù)數(shù)的實(shí)部,將0作為復(fù)數(shù)的虛部 public: friend ostream & operator<< (ostream &out, const complex &c); // 友元函數(shù) private: double m_real; double m_img; }; ostream & operator << (ostream &out, const complex &c){ out << c.m_real << " + " << c.m_img << "i"; return out; } int main(){ complex a(10.0, 20.0); cout << "a = " << a << endl; a = 25.5; // 將賦值的過(guò)程轉(zhuǎn)換成了函數(shù)調(diào)用的過(guò)程 cout << "a = " << a << endl; return 0; } - 轉(zhuǎn)換構(gòu)造函數(shù)也是構(gòu)造函數(shù)的一種,它除了可以用來(lái)將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)類(lèi)型,還可以用來(lái)初始化對(duì)象,這是構(gòu)造函數(shù)本來(lái)的意義。下面創(chuàng)建對(duì)象的方式是正確的:
complex c1(23.1); // 創(chuàng)建具名對(duì)象 complex c2 = 24.3; // 以拷貝的方式初始化對(duì)象,編譯器先調(diào)用轉(zhuǎn)換構(gòu)造函數(shù),將24.3轉(zhuǎn)換為complex類(lèi)型(創(chuàng)建一個(gè)complex類(lèi)的匿名對(duì)象),然后再拷貝給c2。 complex(3.21); // 創(chuàng)建匿名對(duì)象 c1 = complex(34.2); // 創(chuàng)建一個(gè)匿名對(duì)象并將它賦值給 c1 - 如果已經(jīng)對(duì)+運(yùn)算符進(jìn)行了重載,使之能進(jìn)行兩個(gè)complex類(lèi)對(duì)象的相加,那么下面的語(yǔ)句也是正確的:
complex c1(15.6, 89.9); complex c2; c2 = c1 + 29.6; cout << c2 << endl; - 注意:為了獲得目標(biāo)類(lèi)型,編譯器會(huì)“不擇手段”,會(huì)綜合使用內(nèi)置的轉(zhuǎn)換規(guī)則和用戶(hù)自定義的轉(zhuǎn)換規(guī)則,并且會(huì)進(jìn)行多級(jí)類(lèi)型轉(zhuǎn)換,例如:
- 編譯器會(huì)根據(jù)內(nèi)置規(guī)則先將int轉(zhuǎn)換為double,再根據(jù)用戶(hù)自定義規(guī)則將double轉(zhuǎn)換為complex(int --> double --> complex);
- 編譯器會(huì)根據(jù)內(nèi)置規(guī)則先將char轉(zhuǎn)換為int,再將int轉(zhuǎn)換為double,最后根據(jù)用戶(hù)自定義規(guī)則將double轉(zhuǎn)換為complex(char --> int --> double --> complex)
int main(){ complex c1 = 100; //int --> double --> complex cout << c1 << endl; c1 = 'A'; //char --> int --> double --> complex cout << c1 << endl; c1 = true; //bool --> int --> double --> complex cout << c1 << endl; complex c2(25.8, 0.7); //假設(shè)已經(jīng)重載了+運(yùn)算符 c1 = c2 + 'H' + true + 15; //將char、bool、int都轉(zhuǎn)換為complex類(lèi)型再運(yùn)算 cout << c1 << endl; return 0; }
3.再談構(gòu)造函數(shù)
- 構(gòu)造函數(shù)的本意是在創(chuàng)建對(duì)象的時(shí)候初始化對(duì)象,編譯器會(huì)根據(jù)傳遞的實(shí)參來(lái)匹配不同的(重載的)構(gòu)造函數(shù),幾種形式的構(gòu)造函數(shù):
- 默認(rèn)構(gòu)造函數(shù): 就是編譯器自動(dòng)生成的構(gòu)造函數(shù),以complex類(lèi)為例,它的原型為:
complex(); // 沒(méi)參數(shù) - 普通構(gòu)造函數(shù): 就是用戶(hù)自定義的構(gòu)造函數(shù),以complex類(lèi)為例,它的原型為:
complex(double real, double img); // 兩個(gè)參數(shù) - 拷貝構(gòu)造函數(shù): 在以拷貝的方式初始化對(duì)象時(shí)調(diào)用,以complex類(lèi)為例,它的原型為:
complex(const complex &c); - 轉(zhuǎn)換構(gòu)造函數(shù): 將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)類(lèi)型時(shí)調(diào)用,以complex為例,它的原型為:
complex(double real); // 一個(gè)參數(shù)
- 默認(rèn)構(gòu)造函數(shù): 就是編譯器自動(dòng)生成的構(gòu)造函數(shù),以complex類(lèi)為例,它的原型為:
- 不管哪一種構(gòu)造函數(shù),都能夠用來(lái)初始化對(duì)象,這是構(gòu)造函數(shù)的本意。假設(shè)complex類(lèi)定義了以上所有的構(gòu)造函數(shù),那么下面創(chuàng)建對(duì)象的方式都是正確的:
complex c1(); // 調(diào)用complex() complex c2(10, 20); // 調(diào)用complex(double real, double imag) complex c3(c2); // 調(diào)用complex(const complex &c) complex c4(25.7); // 調(diào)用complex(double real) - 除了在創(chuàng)建對(duì)象時(shí)初始化對(duì)象,其他情況下也會(huì)調(diào)用構(gòu)造函數(shù),例如:以拷貝的的方式初始化對(duì)象時(shí)會(huì)調(diào)用拷貝構(gòu)造函數(shù),將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)類(lèi)型時(shí)會(huì)調(diào)用轉(zhuǎn)換構(gòu)造函數(shù)。這些在其他情況下調(diào)用的構(gòu)造函數(shù),就成了特殊的構(gòu)造函數(shù)了。特殊的構(gòu)造函數(shù)并不一定能體現(xiàn)出構(gòu)造函數(shù)的本意。
4.對(duì)complex類(lèi)的進(jìn)一步精簡(jiǎn)
- 上面的complex類(lèi)中我們定義了三個(gè)構(gòu)造函數(shù),其中包括兩個(gè)普通的構(gòu)造函數(shù)和一個(gè)轉(zhuǎn)換構(gòu)造函數(shù)。其實(shí),借助函數(shù)的默認(rèn)參數(shù),我們可以將這三個(gè)構(gòu)造函數(shù)簡(jiǎn)化為一個(gè),請(qǐng)看下面的代碼:
#include "iostream" using namespace std; /*---------------------------將其它類(lèi)型轉(zhuǎn)換為當(dāng)前類(lèi)的類(lèi)型-------------------------------*/ // 如果編譯器不知道轉(zhuǎn)換規(guī)則就不能轉(zhuǎn)換,使用強(qiáng)制類(lèi)型也無(wú)用 class complex{ public: complex(double real=0.0, double img=0.0):m_real(real), m_img(img){} public: friend ostream & operator<< (ostream &out, const complex &c); // 友元函數(shù) private: double m_real; double m_img; }; ostream & operator << (ostream &out, const complex &c){ out << c.m_real << " + " << c.m_img << "i"; return out; } int main(){ complex a(10.0, 20.0); // 向構(gòu)造函數(shù)傳遞2個(gè)實(shí)參,不使用默認(rèn)參數(shù) cout << "a = " << a << endl; complex b(89.5); // 向構(gòu)造函數(shù)傳遞1個(gè)實(shí)參,使用1個(gè)默認(rèn)參數(shù) cout << "b = " << b << endl; complex c; // 不向構(gòu)造函數(shù)傳遞實(shí)參,使用全部默認(rèn)參數(shù) a = 25.5; // 調(diào)用轉(zhuǎn)換構(gòu)造函數(shù)(向構(gòu)造函數(shù)傳遞1個(gè)實(shí)參,使用1個(gè)默認(rèn)參數(shù)) cout << "a = " << a << endl; return 0; }