小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C++類型轉(zhuǎn)換方式總結(jié)

 just_person 2012-03-28

索引目錄

再談為何會有那四個轉(zhuǎn)換運(yùn)算符

看起來,我應(yīng)該把導(dǎo)師講過、遺漏的有關(guān)C++類型轉(zhuǎn)換方面的內(nèi)容都總結(jié)成文了,主要內(nèi)容都在以上幾篇文章中闡述完畢。

上邊的每一篇文章,雖然都單獨(dú)著重強(qiáng)調(diào)一種轉(zhuǎn)換方式或運(yùn)算符,但是也有提到跟其他運(yùn)算符之間的差異性,以及使用建議,因此基本可以看出各個運(yùn)算符的使用方式和作用。

在文章也看到const_cast, reinterpret_cast, static_cast都可以用傳統(tǒng)的轉(zhuǎn)換方式基于指針進(jìn)行替代。如果結(jié)合typeid運(yùn)算符,那么dynamic_cast其實也可以用傳統(tǒng)轉(zhuǎn)換方式實現(xiàn)。

因此不免會有疑惑:這四個轉(zhuǎn)換運(yùn)算符不是很多余。

的確,我剛接觸這些轉(zhuǎn)換運(yùn)算符的時候,我也又這樣的疑慮。因為在跟著導(dǎo)師學(xué)習(xí)C++,做一些課程項目的過程中,我都不曾使用過這些轉(zhuǎn)換運(yùn)算符。一來我需要用到類型轉(zhuǎn)換的地方很少,二來也還不熟悉這些運(yùn)算符,所以就盡量避免使用。

不過在花了這么多時間和精力研究和總結(jié)這些轉(zhuǎn)換運(yùn)算符之后,我以后一定會更多的去使用他們,因為傳統(tǒng)的轉(zhuǎn)換方式能夠?qū)崿F(xiàn)標(biāo)準(zhǔn)轉(zhuǎn)換運(yùn)算符的功能,主要還是基于"C++中的指針可以無條件互相轉(zhuǎn)換"。因此,對于轉(zhuǎn)換符的實現(xiàn),其格式基本都是一致的:用強(qiáng)制轉(zhuǎn)換的方式,直接轉(zhuǎn)換指針類型。

正因如此,看到這些轉(zhuǎn)換代碼,有時候并不能馬上理解其目的用意。而如果用轉(zhuǎn)換運(yùn)算符來操作,就可以一目了然地通過轉(zhuǎn)換符的名稱知道是在去除const,還是想進(jìn)行指針的重新定義。

另一個角度來說,編譯器也對轉(zhuǎn)換運(yùn)算符做來限制、優(yōu)化和異常處理,使用他們可以更好地減少錯誤的產(chǎn)生,以及避免傳統(tǒng)轉(zhuǎn)換沒有達(dá)到預(yù)期的目的。

所以,如果碰到需要類型轉(zhuǎn)換的地方,就盡量思考,是否可以用轉(zhuǎn)換運(yùn)算符來替代,用哪個是最合適的。下邊就來講講什么時候用什么樣的轉(zhuǎn)換符最合適。

轉(zhuǎn)換運(yùn)算符的應(yīng)用之所

結(jié)合網(wǎng)絡(luò)上各個站點看到的關(guān)于C++轉(zhuǎn)換符的知識,以及前面那些文章得到的反饋,可以將各個轉(zhuǎn)換運(yùn)算符的使用總結(jié)如下:

對于傳統(tǒng)的轉(zhuǎn)換方式(C式或函數(shù)式),只在數(shù)值類型(包括整型、浮點型、字符類型和枚舉)上使用。這也是延續(xù)C的形式,當(dāng)然這類轉(zhuǎn)換也是可以用static_cast來替換,但是因為是基本類型,所以傳統(tǒng)轉(zhuǎn)換已經(jīng)很直觀。

對于const_cast轉(zhuǎn)換運(yùn)算符,用在需要去除掉const限定的時候。其實這種情況出現(xiàn)的很少,可能的方法在const_cast一文中已經(jīng)又舉例,不過還是反復(fù)強(qiáng)調(diào), 使用const_cast轉(zhuǎn)換后,絕對不可試圖修改結(jié)果的值。

對于reinterpret_cast轉(zhuǎn)換運(yùn)算符,一般用在將對象指針類型轉(zhuǎn)換到整數(shù)類型或者void * (空指針)。如同在文中舉出的隱患,因此注意的是,若要使用其結(jié)果,一定要將類型轉(zhuǎn)換回去后使用。也不要將隨意的整數(shù)轉(zhuǎn)換成指針類型。

對于static_cast轉(zhuǎn)換運(yùn)算符,將其用在對象的轉(zhuǎn)換之上(雖然static_cast也可以用在有繼承關(guān)系的類型指針之間,但是還是將這方面的轉(zhuǎn)換交給dynamic_cast來操作吧), static_cast會調(diào)用相應(yīng)的構(gòu)造函數(shù)或者重載的轉(zhuǎn)換運(yùn)算符。

通過文章的留言反饋,以及Google C++ Style Guide的推薦格式,知道對于單參構(gòu)造函數(shù)的存在可能會引發(fā)一些隱式的轉(zhuǎn)換,因此用static_cast也可以明確的指出類型的轉(zhuǎn)換過程,避免生成多余的臨時對象造成效率下降。

對于dynamic_cast轉(zhuǎn)換運(yùn)算符,將其用在具有繼承關(guān)系的指針類型之間的轉(zhuǎn)換。無論是從基類到子類的轉(zhuǎn)換,還是子類到基類的轉(zhuǎn)換,都將dynamic_cast套上去,也算是標(biāo)識它們是一家子。

如果任何一種基于指針或引用的轉(zhuǎn)換,套上四個轉(zhuǎn)換運(yùn)算符之后都失敗,那么所要進(jìn)行的轉(zhuǎn)換可能就觸到了"雷區(qū)"了:進(jìn)行了沒意義的轉(zhuǎn)換。比如,對于沒有關(guān)系的兩個類型的指針進(jìn)行了轉(zhuǎn)換,比如試圖轉(zhuǎn)換指向方法的指針了。所以轉(zhuǎn)換運(yùn)算符對于避免代碼出錯也很有幫助。

基于引用(Reference)的轉(zhuǎn)換運(yùn)算符使用

前面的文章中,所以對于轉(zhuǎn)換運(yùn)算符的講述和舉例,都是基于指針的。但實際上,這些轉(zhuǎn)換運(yùn)算符也可以基于引用來展開。準(zhǔn)確說實際上引用類型應(yīng)該是作為轉(zhuǎn)換的目標(biāo)類型,源類型則是對象變量(當(dāng)然也可能用的是引用變量,或是取出指針?biāo)傅膬?nèi)容,它們用到的都是實際的類對象)。

由于引用類型“定義時必須初始化”的特別,使得它不同于指針類型隨時隨地都調(diào)用轉(zhuǎn)換運(yùn)算符,基于引用的轉(zhuǎn)換只在對引用進(jìn)行初始化的時候才會出現(xiàn)。

下邊是const_cast和reinterpret_cast基于引用的運(yùn)用:


    const int int_constant = 21;
    int& int_ref = const_cast<int&>(int_constant);
    cout << int_ref << endl;
    
    int int_value = 7;
    //long& long_ref = int_value; //Error, can not using reference cross types
    float& long_ref = reinterpret_cast<float&> (int_value);
    cout << long_ref << endl;  
    

對于dynamic_cast的應(yīng)用基本也是一致的,只是還是限制在具有繼承關(guān)系的類型之間。不同于基于指針在轉(zhuǎn)換時返回null,dynami_cast在基于引用轉(zhuǎn)換失敗時,會拋出std::bad_cast異常,因為不能將空值賦給引用類型。如果要抓住這個異常,則需要引入如下頭文件:
#include <typeinfo>

而static_cast轉(zhuǎn)換符前面已經(jīng)說過推薦直接用在對象之上,不用在指針上,所以也不太會有需要用在引用類型上的情況出現(xiàn)。

山寨C#的TryParse

C#中有很多簡潔實用的轉(zhuǎn)換方法,比如從字符串到數(shù)值類型的ParseTryParse,還有包含了各種從object對象到數(shù)值類型、時間類型的方法的Convert類,以及檢查繼承關(guān)系的as運(yùn)算符。

從返回的結(jié)果看,C++和dynamic_cast和C#的as很相似,兩者都是在失敗時候返回null。

不過面向?qū)ο蟮年P(guān)鍵點在于什么都是以對象為操作單位,如前所講dynamic_cast看起來更像是一個全局方法。因此我便模仿C#的數(shù)值類的TryParse方法,寫了一個包裹dynamic_cast的類型轉(zhuǎn)換方法:


/////////////////////////////////////////////////////////////////////////////
// dynamic_cast_tryparse.cpp                                                      
// Language:    C++                   
// Complier:    Visual Studio 2010, Xcode3.2.6 
// Platform:    MacBook Pro 2010
// Application: none  
// Author:      Ider, Syracuse University, ider.cs@gmail.com
///////////////////////////////////////////////////////////////////////////
#include <string>
#include <iostream>
using namespace std;

class Parents
{
public:
    Parents(string n="Parent"){ name = n;}
    virtual ~Parents(){}
    
    virtual void Speak()
    {
        cout << "\tI am " << name << ", I love my children." << endl;
    }
    void Work()
    {
        cout << "\tI am " << name <<", I need to work for my family." << endl;;
    }
    
    /************** TryParseTo **************/
    template<typename T> bool TryParseTo(T** outValue)
    {
        T* temp = dynamic_cast<T*> (this);
        if (temp == NULL) return false;
        
        *outValue = temp;
        return true;
    }
    
protected:
    string name;
};

class Children : public Parents
{
public:
    Children(string n="Child"):Parents(n){ }
    
    virtual ~Children(){}
    
    virtual void Speak()
    {
        cout << "\tI am " << name << ", I love my parents." << endl;
    }
    /*
     **Children inherit Work() method from parents,
     **it could be treated like part-time job.
     */
    void Study()
    {
        cout << "\tI am " << name << ", I need to study for future." << endl;;
    }
    
private:
    //string name; //Inherit "name" member from Parents
};

class Stranger 
{
public:
    Stranger(string n="stranger"){name = n;}
    virtual ~Stranger(){}
    
    void Self_Introduce()
    {
        cout << "\tI am a stranger" << endl;
    }
    void Speak()
    {
        //cout << "I am a stranger" << endl;
        cout << "\tDo not talk to "<< name << ", who is a stranger." << endl;
    }
private:
    string name;
};

int main() 
{

    Children * parsedChild;
    Parents * parsedParent;
    Stranger * parsedStranger;
    
    Parents * mother = new Parents("Mother who pretend to be a my daugher");
    if(mother->TryParseTo<Children>(&parsedChild))
        parsedChild->Speak();
    else
        cout << "Parents parse to Children failed" << endl;
    
    delete mother;
    
    mother = new Children("Daughter who pretend to be a my mother");
    if(mother->TryParseTo<Children>(&parsedChild))
        parsedChild->Speak();
    else
        cout << "Parents parse to Children failed" << endl;
    
    delete mother;
    
    Children * son = new Children("Son who pretend to be a my father");
    if(son->TryParseTo<Parents>(&parsedParent))
        parsedParent->Speak();
    else
        cout << "Children parse to Parents failed" << endl;
    
    if(son->TryParseTo<Stranger>(&parsedStranger))
        parsedStranger->Speak();
    else
        cout << "Children parse to Stranger failed" << endl;
    
    delete son;
    
    //pointer of child class could pointer to base class object
    
    /* 
    * son = new Parents("Father who pretend to be a my son");
    if(son->TryParseTo<Parents>(&parsedParent))
        parsedParent->Speak();
    else
        cout << "Parse failed" << endl;
    
    delete son;
    */

    return 0;
}

/********************* Result *********************/

//Parents parse to Children failed
//    I am Daughter who pretend to be a my mother, I love my parents.
//    I am Son who pretend to be a my father, I love my parents.
//Children parse to Stranger failed
  
  

這段代碼中使用到的類跟dynamic_cast一文中使用的基本一樣,只是在基類中多了一個模板方法:


    template<typename T> bool TryParseTo(T** outValue)
    {
        T* temp = dynamic_cast<T*> (this);
        if (temp == NULL) return false;
        
        *outValue = temp;
        return true;
    }
    

該方法需要指定的目標(biāo)類型,將自身指針轉(zhuǎn)換成目標(biāo)指針。轉(zhuǎn)換成功,則將結(jié)果賦值給相應(yīng)的變量,并返回真值;若失敗則返回假值,不改變指針變量。因為要讓外部的指針變量能夠接受到改值,因此不得不使用指向指針的指針。

因為在基類中以公共結(jié)果的形式出現(xiàn),所以每一個子類都繼承了該方法,無論是基類的對象還是子類的對象都可以調(diào)用該方法。而該方法又不是虛方法,因此不并不希望子類去修改它。只是因為方法是模板方法,可能在編譯的時候需要多花一些時間。

由于引用必須在定義時就賦值,并且dynamic_cast對于基于引用的轉(zhuǎn)換不成功時將拋出異常,因此對于基于引用的轉(zhuǎn)換,我還沒有想出有什么好的山寨形式。

從測試代碼的結(jié)果也可以看出,對于該發(fā)放的調(diào)用都是成功有效的。

所以又應(yīng)了導(dǎo)師常說的一句話: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.

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多