MoreEffectiveC++:類型轉(zhuǎn)換

字號(hào):

仔細(xì)想想地位卑賤的類型轉(zhuǎn)換功能(cast),其在程序設(shè)計(jì)中的地位就象goto語句一樣令人鄙視。但是它還不是無法令人忍受,因?yàn)楫?dāng)在某些緊要的關(guān)頭,類型轉(zhuǎn)換還是必需的,這時(shí)它是一個(gè)必需品。
    不過C風(fēng)格的類型轉(zhuǎn)換并不代表所有的類型轉(zhuǎn)換功能。一來它們過于粗魯,能允許你在任何類型之間進(jìn)行轉(zhuǎn)換。不過如果要進(jìn)行更精確的類型轉(zhuǎn)換,這會(huì)是一個(gè)優(yōu)點(diǎn)。在這些類型轉(zhuǎn)換中存在著巨大的不同,例如把一個(gè)指向const對(duì)象的指針(pointer-to-const-object)轉(zhuǎn)換成指向非const對(duì)象的指針(pointer-to-non-const-object)(即一個(gè)僅僅去除cosnt的類型轉(zhuǎn)換),把一個(gè)指向基類的指針轉(zhuǎn)換成指向子類的指針(即完全改變對(duì)象類型)。傳統(tǒng)的C風(fēng)格的類型轉(zhuǎn)換不對(duì)上述兩種轉(zhuǎn)換進(jìn)行區(qū)分。(這一點(diǎn)也不令人驚訝,因?yàn)镃風(fēng)格的類型轉(zhuǎn)換是為C語言設(shè)計(jì)的,而不是為C++語言設(shè)計(jì)的)。
    二來C風(fēng)格的類型轉(zhuǎn)換在程序語句中難以識(shí)別。在語法上類型轉(zhuǎn)換由圓括號(hào)和標(biāo)識(shí)符組成,而這些可以用在C++中的任何地方。這使得回答象這樣一個(gè)最基本的有關(guān)類型轉(zhuǎn)換的問題變得很困難,“在這個(gè)程序中是否使用了類型轉(zhuǎn)換?”。這是因?yàn)槿斯ら喿x很可能忽略了類型轉(zhuǎn)換的語句,而利用象grep的工具程序也不能從語句構(gòu)成上區(qū)分出它們來。
    C++通過引進(jìn)四個(gè)新的類型轉(zhuǎn)換操作符克服了C風(fēng)格類型轉(zhuǎn)換的缺點(diǎn),這四個(gè)操作符是,static_cast, const_cast, dynamic_cast, 和reintERPret_cast。在大多數(shù)情況下,對(duì)于這些操作符你只需要知道原來你習(xí)慣于這樣寫,(type) expression而現(xiàn)在你總應(yīng)該這樣寫: static_cast(expression);例如,假設(shè)你想把一個(gè)int轉(zhuǎn)換成double,以便讓包含int類型變量的表達(dá)式產(chǎn)生出浮點(diǎn)數(shù)值的結(jié)果。如果用C風(fēng)格的類型轉(zhuǎn)換,你能這樣寫:
    int firstNumber, secondNumber;
    ...
    double result = ((double)firstNumber)/secondNumber;
    如果用上述新的類型轉(zhuǎn)換方法,你應(yīng)該這樣寫:
    double result = static_cast(firstNumber)/secondNumber;
    這樣的類型轉(zhuǎn)換不論是對(duì)人工還是對(duì)程序都很容易識(shí)別。
    static_cast 在功能上基本上與C風(fēng)格的類型轉(zhuǎn)換一樣強(qiáng)大,含義也一樣。它也有功能上限制。例如,你不能用static_cast象用C風(fēng)格的類型轉(zhuǎn)換一樣把struct轉(zhuǎn)換成int類型或者把double類型轉(zhuǎn)換成指針類型,另外,static_cast不能從表達(dá)式中去除const屬性,因?yàn)榱硪粋€(gè)新的類型轉(zhuǎn)換操作符const_cast有這樣的功能。
    其它新的C++類型轉(zhuǎn)換操作符被用在需要更多限制的地方。const_cast 用于類型轉(zhuǎn)換掉表達(dá)式的const或volatileness屬性。通過使用const_cast,你向人們和編譯器強(qiáng)調(diào)你通過類型轉(zhuǎn)換想做的只是改變一些東西的constness 或者 volatileness屬性。這個(gè)含義被編譯器所約束。如果你試圖使用const_cast來完成修改constness 或者 volatileness屬性之外的事情,你的類型轉(zhuǎn)換將被拒絕。下面是一些例子:
    class Widget { ... };
    class SpecialWidget: public Widget { ... };
    void update(SpecialWidget *psw);
    SpecialWidget sw; // sw 是一個(gè)非const 對(duì)象。
    const SpecialWidget& csw = sw; // csw 是sw的一個(gè)引用
    // 它是一個(gè)const 對(duì)象
    update(&csw); // 錯(cuò)誤!不能傳遞一個(gè)const SpecialWidget* 變量
    // 給一個(gè)處理SpecialWidget*類型變量的函數(shù)
    update(const_cast(&csw));
    // 正確,csw的const被顯示地轉(zhuǎn)換掉(
    // csw和sw兩個(gè)變量值在update
    //函數(shù)中能被更新)
    update((SpecialWidget*)&csw);
    // 同上,但用了一個(gè)更難識(shí)別
    //的C風(fēng)格的類型轉(zhuǎn)換
    Widget *pw = new SpecialWidget;
    update(pw); // 錯(cuò)誤!pw的類型是Widget*,但是
    // update函數(shù)處理的是SpecialWidget*類型
    update(const_cast(pw));
    // 錯(cuò)誤!const_cast僅能被用在影響
    // constness or volatileness的地方上。,
    // 不能用在向繼承子類進(jìn)行類型轉(zhuǎn)換。
    到目前為止,const_cast最普通的用途就是轉(zhuǎn)換掉對(duì)象的const屬性。