索引目錄再談為何會(huì)有那四個(gè)轉(zhuǎn)換運(yùn)算符看起來(lái),我應(yīng)該把導(dǎo)師講過(guò)、遺漏的有關(guān)C++類(lèi)型轉(zhuǎn)換方面的內(nèi)容都總結(jié)成文了,主要內(nèi)容都在以上幾篇文章中闡述完畢。 上邊的每一篇文章,雖然都單獨(dú)著重強(qiáng)調(diào)一種轉(zhuǎn)換方式或運(yùn)算符,但是也有提到跟其他運(yùn)算符之間的差異性,以及使用建議,因此基本可以看出各個(gè)運(yùn)算符的使用方式和作用。 在文章也看到const_cast, reinterpret_cast, static_cast都可以用傳統(tǒng)的轉(zhuǎn)換方式基于指針進(jìn)行替代。如果結(jié)合typeid運(yùn)算符,那么dynamic_cast其實(shí)也可以用傳統(tǒng)轉(zhuǎn)換方式實(shí)現(xiàn)。 因此不免會(huì)有疑惑:這四個(gè)轉(zhuǎn)換運(yùn)算符不是很多余。 的確,我剛接觸這些轉(zhuǎn)換運(yùn)算符的時(shí)候,我也又這樣的疑慮。因?yàn)樵诟鴮?dǎo)師學(xué)習(xí)C++,做一些課程項(xiàng)目的過(guò)程中,我都不曾使用過(guò)這些轉(zhuǎn)換運(yùn)算符。一來(lái)我需要用到類(lèi)型轉(zhuǎn)換的地方很少,二來(lái)也還不熟悉這些運(yùn)算符,所以就盡量避免使用。 不過(guò)在花了這么多時(shí)間和精力研究和總結(jié)這些轉(zhuǎn)換運(yùn)算符之后,我以后一定會(huì)更多的去使用他們,因?yàn)閭鹘y(tǒng)的轉(zhuǎn)換方式能夠?qū)崿F(xiàn)標(biāo)準(zhǔn)轉(zhuǎn)換運(yùn)算符的功能,主要還是基于"C++中的指針可以無(wú)條件互相轉(zhuǎn)換"。因此,對(duì)于轉(zhuǎn)換符的實(shí)現(xiàn),其格式基本都是一致的:用強(qiáng)制轉(zhuǎn)換的方式,直接轉(zhuǎn)換指針類(lèi)型。 正因如此,看到這些轉(zhuǎn)換代碼,有時(shí)候并不能馬上理解其目的用意。而如果用轉(zhuǎn)換運(yùn)算符來(lái)操作,就可以一目了然地通過(guò)轉(zhuǎn)換符的名稱(chēng)知道是在去除const,還是想進(jìn)行指針的重新定義。 另一個(gè)角度來(lái)說(shuō),編譯器也對(duì)轉(zhuǎn)換運(yùn)算符做來(lái)限制、優(yōu)化和異常處理,使用他們可以更好地減少錯(cuò)誤的產(chǎn)生,以及避免傳統(tǒng)轉(zhuǎn)換沒(méi)有達(dá)到預(yù)期的目的。 所以,如果碰到需要類(lèi)型轉(zhuǎn)換的地方,就盡量思考,是否可以用轉(zhuǎn)換運(yùn)算符來(lái)替代,用哪個(gè)是最合適的。下邊就來(lái)講講什么時(shí)候用什么樣的轉(zhuǎn)換符最合適。 轉(zhuǎn)換運(yùn)算符的應(yīng)用之所結(jié)合網(wǎng)絡(luò)上各個(gè)站點(diǎn)看到的關(guān)于C++轉(zhuǎn)換符的知識(shí),以及前面那些文章得到的反饋,可以將各個(gè)轉(zhuǎn)換運(yùn)算符的使用總結(jié)如下: 對(duì)于傳統(tǒng)的轉(zhuǎn)換方式(C式或函數(shù)式),只在數(shù)值類(lèi)型(包括整型、浮點(diǎn)型、字符類(lèi)型和枚舉)上使用。這也是延續(xù)C的形式,當(dāng)然這類(lèi)轉(zhuǎn)換也是可以用static_cast來(lái)替換,但是因?yàn)槭腔绢?lèi)型,所以傳統(tǒng)轉(zhuǎn)換已經(jīng)很直觀。 對(duì)于const_cast轉(zhuǎn)換運(yùn)算符,用在需要去除掉const限定的時(shí)候。其實(shí)這種情況出現(xiàn)的很少,可能的方法在const_cast一文中已經(jīng)又舉例,不過(guò)還是反復(fù)強(qiáng)調(diào), 使用const_cast轉(zhuǎn)換后,絕對(duì)不可試圖修改結(jié)果的值。 對(duì)于reinterpret_cast轉(zhuǎn)換運(yùn)算符,一般用在將對(duì)象指針類(lèi)型轉(zhuǎn)換到整數(shù)類(lèi)型或者void * (空指針)。如同在文中舉出的隱患,因此注意的是,若要使用其結(jié)果,一定要將類(lèi)型轉(zhuǎn)換回去后使用。也不要將隨意的整數(shù)轉(zhuǎn)換成指針類(lèi)型。 對(duì)于static_cast轉(zhuǎn)換運(yùn)算符,將其用在對(duì)象的轉(zhuǎn)換之上(雖然static_cast也可以用在有繼承關(guān)系的類(lèi)型指針之間,但是還是將這方面的轉(zhuǎn)換交給dynamic_cast來(lái)操作吧), static_cast會(huì)調(diào)用相應(yīng)的構(gòu)造函數(shù)或者重載的轉(zhuǎn)換運(yùn)算符。 通過(guò)文章的留言反饋,以及Google C++ Style Guide的推薦格式,知道對(duì)于單參構(gòu)造函數(shù)的存在可能會(huì)引發(fā)一些隱式的轉(zhuǎn)換,因此用static_cast也可以明確的指出類(lèi)型的轉(zhuǎn)換過(guò)程,避免生成多余的臨時(shí)對(duì)象造成效率下降。 對(duì)于dynamic_cast轉(zhuǎn)換運(yùn)算符,將其用在具有繼承關(guān)系的指針類(lèi)型之間的轉(zhuǎn)換。無(wú)論是從基類(lèi)到子類(lèi)的轉(zhuǎn)換,還是子類(lèi)到基類(lèi)的轉(zhuǎn)換,都將dynamic_cast套上去,也算是標(biāo)識(shí)它們是一家子。 如果任何一種基于指針或引用的轉(zhuǎn)換,套上四個(gè)轉(zhuǎn)換運(yùn)算符之后都失敗,那么所要進(jìn)行的轉(zhuǎn)換可能就觸到了"雷區(qū)"了:進(jìn)行了沒(méi)意義的轉(zhuǎn)換。比如,對(duì)于沒(méi)有關(guān)系的兩個(gè)類(lèi)型的指針進(jìn)行了轉(zhuǎn)換,比如試圖轉(zhuǎn)換指向方法的指針了。所以轉(zhuǎn)換運(yùn)算符對(duì)于避免代碼出錯(cuò)也很有幫助。 基于引用(Reference)的轉(zhuǎn)換運(yùn)算符使用前面的文章中,所以對(duì)于轉(zhuǎn)換運(yùn)算符的講述和舉例,都是基于指針的。但實(shí)際上,這些轉(zhuǎn)換運(yùn)算符也可以基于引用來(lái)展開(kāi)。準(zhǔn)確說(shuō)實(shí)際上引用類(lèi)型應(yīng)該是作為轉(zhuǎn)換的目標(biāo)類(lèi)型,源類(lèi)型則是對(duì)象變量(當(dāng)然也可能用的是引用變量,或是取出指針?biāo)傅膬?nèi)容,它們用到的都是實(shí)際的類(lèi)對(duì)象)。 由于引用類(lèi)型“定義時(shí)必須初始化”的特別,使得它不同于指針類(lèi)型隨時(shí)隨地都調(diào)用轉(zhuǎn)換運(yùn)算符,基于引用的轉(zhuǎn)換只在對(duì)引用進(jìn)行初始化的時(shí)候才會(huì)出現(xiàn)。 下邊是const_cast和reinterpret_cast基于引用的運(yùn)用:
對(duì)于dynamic_cast的應(yīng)用基本也是一致的,只是還是限制在具有繼承關(guān)系的類(lèi)型之間。不同于基于指針在轉(zhuǎn)換時(shí)返回null,dynami_cast在基于引用轉(zhuǎn)換失敗時(shí),會(huì)拋出std::bad_cast異常,因?yàn)椴荒軐⒖罩蒂x給引用類(lèi)型。如果要抓住這個(gè)異常,則需要引入如下頭文件: 而static_cast轉(zhuǎn)換符前面已經(jīng)說(shuō)過(guò)推薦直接用在對(duì)象之上,不用在指針上,所以也不太會(huì)有需要用在引用類(lèi)型上的情況出現(xiàn)。 山寨C#的TryParseC#中有很多簡(jiǎn)潔實(shí)用的轉(zhuǎn)換方法,比如從字符串到數(shù)值類(lèi)型的Parse和TryParse,還有包含了各種從object對(duì)象到數(shù)值類(lèi)型、時(shí)間類(lèi)型的方法的Convert類(lèi),以及檢查繼承關(guān)系的as運(yùn)算符。 從返回的結(jié)果看,C++和dynamic_cast和C#的as很相似,兩者都是在失敗時(shí)候返回null。 不過(guò)面向?qū)ο蟮年P(guān)鍵點(diǎn)在于什么都是以對(duì)象為操作單位,如前所講dynamic_cast看起來(lái)更像是一個(gè)全局方法。因此我便模仿C#的數(shù)值類(lèi)的TryParse方法,寫(xiě)了一個(gè)包裹dynamic_cast的類(lèi)型轉(zhuǎn)換方法:
這段代碼中使用到的類(lèi)跟dynamic_cast一文中使用的基本一樣,只是在基類(lèi)中多了一個(gè)模板方法:
該方法需要指定的目標(biāo)類(lèi)型,將自身指針轉(zhuǎn)換成目標(biāo)指針。轉(zhuǎn)換成功,則將結(jié)果賦值給相應(yīng)的變量,并返回真值;若失敗則返回假值,不改變指針變量。因?yàn)橐屚獠康闹羔樧兞磕軌蚪邮艿礁闹?,因此不得不使用指向指針的指針?/p> 因?yàn)樵诨?lèi)中以公共結(jié)果的形式出現(xiàn),所以每一個(gè)子類(lèi)都繼承了該方法,無(wú)論是基類(lèi)的對(duì)象還是子類(lèi)的對(duì)象都可以調(diào)用該方法。而該方法又不是虛方法,因此不并不希望子類(lèi)去修改它。只是因?yàn)榉椒ㄊ悄0宸椒?,可能在編譯的時(shí)候需要多花一些時(shí)間。 由于引用必須在定義時(shí)就賦值,并且dynamic_cast對(duì)于基于引用的轉(zhuǎn)換不成功時(shí)將拋出異常,因此對(duì)于基于引用的轉(zhuǎn)換,我還沒(méi)有想出有什么好的山寨形式。 從測(cè)試代碼的結(jié)果也可以看出,對(duì)于該發(fā)放的調(diào)用都是成功有效的。 所以又應(yīng)了導(dǎo)師常說(shuō)的一句話:When use C++, the good news is that you can do everything you want, the bad news is that you have to do everything you want. |
|
來(lái)自: just_person > 《類(lèi)型轉(zhuǎn)換》