• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Jiang's C++ Space

            創(chuàng)作,也是一種學(xué)習(xí)的過程。

               :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::

            三年前有場筆試,(注:三年前我在blog.csdn.net上發(fā)表過一篇同樣標(biāo)題的文章,本想直接轉(zhuǎn)過來,但發(fā)現(xiàn)其中很多不妥之處,因此重寫)其中碰到一道題目,讓我列舉C++中的四種cast的轉(zhuǎn)換分別是什么,有何作用,并舉例說明,我雖然早知道C++有四種cast轉(zhuǎn)換,但平常使用非常少也就沒注意,所以那題我是沒做出來,回來后打算對C++的這些類型轉(zhuǎn)換方法進(jìn)行小結(jié),我做了許多實驗,于是有此文,希望對你有些幫助。

            下文中的“常規(guī)類型”指的是int、double、float、bool……這些非結(jié)構(gòu)化類型,也就是不包括struct和class類型。“舊式轉(zhuǎn)換”指的是C語言風(fēng)格的“(NewType)(Val)”方式的轉(zhuǎn)換。

            1、指針=>常規(guī)類型

            比如我們需要打印一個指針的值(它指向的地址)的時候,我們指針直接轉(zhuǎn)換為整數(shù),用printf輸出個16進(jìn)制的地址。我們可以用舊式轉(zhuǎn)換,或者reinterpret_cast,其它轉(zhuǎn)換都是不可以的。

                CIndepend oIndepend;
                CIndepend 
            * pIndepend = &oIndepend;
                unsigned 
            char cTest= (unsigned char )pIndepend;
                unsigned 
            short sTest = (unsigned short )pIndepend;
                unsigned 
            int iTest = (unsigned int )pIndepend;

            在32位系統(tǒng)中,指針其實是個32位的無符號整型,要正常輸出指針的值,正確做法是把它轉(zhuǎn)換為一個無符號32位整形數(shù)輸出(有符號的可能導(dǎo)致輸出不正確),如果轉(zhuǎn)換為一個16位的,或者8位的,那將丟失數(shù)據(jù),當(dāng)然了,前面這段代碼不會出現(xiàn)任何error和warning,你知道你在干什么即可。剛說了,我們除了舊式轉(zhuǎn)換還可以用reinterpret_cast,于是上面的代碼可以這樣寫:

                unsigned char cTest= reinterpret_cast<unsigned char >(pIndepend);
                unsigned 
            short sTest = reinterpret_cast<unsigned short>(pIndepend);
                unsigned 
            int iTest = reinterpret_cast<unsigned int>(pIndepend);

            也是沒有任何問題的,運行效果一樣,那我們能不能把指針轉(zhuǎn)換為浮點型呢?這樣:

                float fTest = reinterpret_cast<float>(pIndepend);
                
            double dTest = reinterpret_cast<double>(pIndepend);

            不行,你試試看就知道了,你會得到這樣的編譯錯誤:

            error C2440: 'reinterpret_cast' : cannot convert from 'class CIndepend *' to 'float'
                    There is no context in which this conversion is possible
            error C2440: 'reinterpret_cast' : cannot convert from 'class CIndepend *' to 'double'
                    There is no context in which this conversion is possible

            其實將指針轉(zhuǎn)換為浮點數(shù)這種做法就很怪異嘛,你不覺得嗎?這樣有什么用啊?不過你一定要這樣干的話也不是沒有辦法,看代碼:

                float fTest = reinterpret_cast<float &>(pIndepend);
                
            double dTest = reinterpret_cast<double &>(pIndepend);

            加個小小的“&”符號就可以了,C++會不顧一切地把pIndepend這個變量當(dāng)作一個float和double,把指針的值“理解”為float和double,當(dāng)然,這樣獲得的浮點數(shù)的值是沒什么實際意義的,因為指針的值是32位無符號整型,而浮點數(shù)有它自己特定的格式,這么一轉(zhuǎn)換就牛頭不對馬嘴。你還可以這樣寫:

                  float fTest = (float &)pIndepend;
                  
            double dTest = (double &)pIndepend;

            效果一樣,得到的也是無意義的值。

            2、常規(guī)類型=>指針

            就是反過來羅,可能不說大家都能猜到結(jié)果了。把常規(guī)類型轉(zhuǎn)換為指針有什么用呢?可能有點用,比如我們在某些特殊的場合要求一個指針指向一個特別的地址,這時候我們可以直接給指針賦個值,當(dāng)然了,這個值應(yīng)該是整型:

                CIndepend * pIndepend;

                
            char cVal = 1;
                
            short sVal = 2;
                
            int iVal = 3;

                pIndepend 
            = (CIndepend *)cVal;
                pIndepend 
            = (CIndepend *)sVal;
                pIndepend 
            = (CIndepend *)iVal;

            這樣是沒問題的,那浮點數(shù)呢?——又來了,浮點數(shù)轉(zhuǎn)換為指針?這怎么算啊?顯然這是不行的,如果真的需要“轉(zhuǎn)換”,那就先把浮點數(shù)轉(zhuǎn)換為整型,然后再賦值給指針吧。這個時候,dynamic_cast和static_cast都是不行的。

            3、基本類型轉(zhuǎn)換

            比如int轉(zhuǎn)換為float,char轉(zhuǎn)變?yōu)閟hort,很多時候我們都“默認(rèn)”了這種轉(zhuǎn)換,即使沒有顯式指定用舊式轉(zhuǎn)換還是static_cast。在這種類型的轉(zhuǎn)換中,舊式轉(zhuǎn)換和static_cast的表現(xiàn)非常地類似:

                double dVal = 5.0;

                
            char cVal = static_cast<char>(dVal);
                
            short sVal = static_cast<short>(dVal);
                
            int iVal = static_cast<int>(dVal);

                cVal 
            = (char)(dVal);
                sVal 
            = (short)(dVal);
                iVal 
            = (int)(dVal);

            而dynamic_cast還是不可行,那……reinterpret_cast呢?不妨試試看:

                double dVal = 5.0;

                
            char cVal = reinterpret_cast<char>(dVal);
                
            short sVal = reinterpret_cast<short>(dVal);
                
            int iVal = reinterpret_cast<int>(dVal);

            一編譯,就出下面的錯誤:

            error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'char'
                    Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast
            error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'short'
                    Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast
            error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'int'
                    Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast

            說這是個有效標(biāo)準(zhǔn)轉(zhuǎn)換,請使用static_cast或者C風(fēng)格的舊式轉(zhuǎn)換。reinterpret_cast不是號稱最寬松的轉(zhuǎn)換么?怎么不行了?你一定要它行也是沒問題的,和前面的那樣,加個“&”符號:

                char cVal = reinterpret_cast<char &>(dVal);
                
            short sVal = reinterpret_cast<short &>(dVal);
                
            int iVal = reinterpret_cast<int &>(dVal);

            但結(jié)果并不是你想要的結(jié)果,因為這樣reinterpret_cast會不管三七二十一,直接把dVal的東西當(dāng)作是一個char,short和int,很明顯,double是有一定的格式的,將double直接“理解”為char,short或者int一定會有問題。

            4、class的轉(zhuǎn)換

            上一節(jié)說的是基本類型,那對于類呢?一個類直接轉(zhuǎn)換為另一個類,這看起來確實有些荒謬,不過強(qiáng)大而靈活的C++卻偏偏允許了這種行為。看代碼:

            class CBase
            {
            public:
                CBase(){};
                
            int m_iBase;
            };

            class CIndepend
            {
            public:
                CIndepend(){};
                
            int m_iIndepend;
            };

            int main(int argc, char* argv[])
            {
                CBase oBase;
                CIndepend oIndepend 
            = reinterpret_cast<CIndepend &>(oBase);
                
            return 0;
            }

            居然編譯過去了,運行貌似也沒什么問題,當(dāng)然轉(zhuǎn)換過程和前面的差不多,就是把oBase理解為一個CIndepend對象,這個賦值運算執(zhí)行“位拷貝”,這種方式的轉(zhuǎn)換在實際中是碰不到的,起碼我想不出有什么理由使用它。這種情況下,其它的轉(zhuǎn)換方式都是不可行的。

            5、class=>指針 or 指針=>class

            這種行為更怪異,class直接理解為指針?這其實是不可行的,跟前面提到的浮點數(shù)轉(zhuǎn)換為指針一樣,如果實在需要,就把class轉(zhuǎn)變?yōu)檎停缓笳娃D(zhuǎn)換為指針:

            CIndepend * pIndepend = reinterpret_cast<CIndepend *>(reinterpret_cast<unsigned int &>(oBase));

            可這……這啥意思呢?哈哈,別問我。反過來,指針轉(zhuǎn)換為class恐怕也令人費解:

                CDerived oDerived;
                CDerived 
            *pDerived = &oDerived;
                CIndepend oIndepend 
            = reinterpret_cast<CIndepend &>(pDerived);

            能擔(dān)當(dāng)起這種怪異的工作的,唯reinterpret_cast是也,這樣會產(chǎn)生什么后果呢?指針是個32位無符號整型,將它強(qiáng)制理解為一個CIndepend,然后作位拷貝,理所當(dāng)然,oIndepend的值會被改變,而且還有訪問越界的風(fēng)險,導(dǎo)致內(nèi)容混亂甚至程序崩潰。

            6、指針之間的轉(zhuǎn)換

            前面一直沒提起的一種轉(zhuǎn)換就是dynamic_cast,因為它是最為嚴(yán)格的一種轉(zhuǎn)換,它只能完成指針到指針的轉(zhuǎn)換,而且還有限制。看這個:

                CDerived oDerived;
                CDerived 
            *pDerived = &oDerived;
                
            CIndepend *pIndepend = dynamic_cast<CIndepend *>(pDerived);

            編譯出錯了:

            error C2683: dynamic_cast : 'CDerived' is not a polymorphic type
                    D:\work\CastTest\CastTest.cpp(13) : see declaration of 'CDerived'

            因為CDerived和CIndepend沒有繼承關(guān)系,把dynamic_cast換成static_cast還是不行的,會出另外一個錯:

            error C2440: 'static_cast' : cannot convert from 'class CDerived *' to 'class CIndepend *'
                    Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

            編譯器說這是沒有關(guān)系的兩個指針,應(yīng)該用reinterpret_cast或者C風(fēng)格的舊式轉(zhuǎn)換,再看:

                //CDerived是CBase的子類
                CBase oBase;
                CBase 
            *pBase = &oBase;
                CDerived 
            *pDerived = dynamic_cast<CDerived *>(pBase);

            基類指針轉(zhuǎn)換為子類指針,行不行呢?出錯,錯誤跟剛才的一樣,記住,dynamic_cast僅僅可以把子類指針轉(zhuǎn)換為基類指針,別的都不行!上面這段代碼如果不用dynamic_cast,而是用static_cast,就能編譯通過,static_cast的要求來得比較寬松。

            OK,到這里為止,大家都知道什么時候用什么轉(zhuǎn)換是可以的了,問題是C++為什么搞出怎么多轉(zhuǎn)換出來呢?我想很大程度上是兼顧了安全性和靈活性,要想安全,class指針的轉(zhuǎn)換就使用dynamic_cast;一般情況下我們認(rèn)為,static_cast也是安全的;C風(fēng)格的舊式轉(zhuǎn)換則靈活一些,它允許任意類型指針之間的轉(zhuǎn)換;而reinterpret_cast就更加了,什么亂七八糟都可以。那從功能強(qiáng)弱上排個序,我想從強(qiáng)到弱應(yīng)該是:reinterpret_cast,舊式轉(zhuǎn)換,static_cast,dynamic_cast。

            Oh,還有一種轉(zhuǎn)換,差點忘了,就是const_cast,不過這種轉(zhuǎn)換比較特別,可以獨立開來,它的功能就是去除一個變量的const屬性,也就是說,允許修改常量的值,哈哈,修改常量的值?既然要修改常量的值,那為什么還要聲明它為常量?——這也是C++靈活的一個體現(xiàn)。不過const_cast其實有個問題,有時候它并不能真正改變一個常量的值,關(guān)于這個,在我的另一篇博文中有講述,此文還在csdn.net,晚些時候移過來,我再給個鏈接。

            posted on 2009-04-23 18:02 Jiang Guogang 閱讀(1781) 評論(0)  編輯 收藏 引用 所屬分類: Knowledge
            久久精品国产亚洲av麻豆小说 | 国产亚洲精午夜久久久久久| 亚洲综合精品香蕉久久网| 久久综合亚洲色一区二区三区| 久久精品国产亚洲αv忘忧草| 蜜臀av性久久久久蜜臀aⅴ麻豆| 国产精品久久久久无码av | 亚洲欧美一区二区三区久久| 久久中文字幕人妻丝袜| 久久福利青草精品资源站免费| 久久有码中文字幕| 97精品国产91久久久久久| 久久久精品日本一区二区三区| 午夜精品久久久久久中宇| 久久精品不卡| 欧美久久综合性欧美| 免费无码国产欧美久久18| 国产99久久久国产精免费| 亚洲国产精品无码久久| 久久精品这里只有精99品| 69久久夜色精品国产69| 久久婷婷五月综合国产尤物app| 韩国三级中文字幕hd久久精品| 久久99国产乱子伦精品免费| 久久久久av无码免费网| 久久免费视频6| 久久精品国产一区二区三区不卡| 国产精品久久久亚洲| 亚洲精品乱码久久久久久蜜桃不卡| 欧美午夜精品久久久久久浪潮| 久久中文娱乐网| 亚洲乱亚洲乱淫久久| 久久精品国产影库免费看| 人妻精品久久久久中文字幕69| 久久久久波多野结衣高潮| 久久亚洲精品无码aⅴ大香| 亚洲国产天堂久久久久久 | 久久噜噜电影你懂的| 99久久777色| 伊人久久大香线蕉影院95| 国产一级做a爰片久久毛片|