2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

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

 just_person 2012-03-28

索引目錄

再談為何會(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)用:


    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;  
    

對(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è)異常,則需要引入如下頭文件:
#include <typeinfo>

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

山寨C#的TryParse

C#中有很多簡(jiǎn)潔實(shí)用的轉(zhuǎn)換方法,比如從字符串到數(shù)值類(lèi)型的ParseTryParse,還有包含了各種從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)換方法:


/////////////////////////////////////////////////////////////////////////////
// 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
  
  

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


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

該方法需要指定的目標(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.

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多