c++類型轉換static_cast, dynamic_cast, reinterpret_cast, const_cast區(qū)別比較捐名,顯示轉換旦万,隱式轉換

1.實現隱式類類型轉換

short a=2000;

int b;

b=a;

short是兩字節(jié),int是四字節(jié)镶蹋,由short型轉成int型是寬化轉換(bit位數增多)成艘,編譯器沒有warning赏半,如下圖所示。寬化轉換(如char到int淆两,int到long long断箫,int到float,float到double秋冰,int到double等)構成隱式轉換仲义,編譯器允許直接轉換。

但若

double a=2000;

short b;

b=a;

是從8字節(jié)的double型轉成2字節(jié)的short型變量剑勾,是窄化轉換埃撵,編譯器就會有warning了,如下所示甥材,提醒程序員可能丟失數據盯另。不過需要注意的是,有些隱式轉換洲赵,編譯器可能并不給出warning鸳惯,比如int到short,但數據溢出卻依然會發(fā)生叠萍。

隱式轉換一

使用單參數的構造函數或N個參數中有N-1個是默認參數的構造函數芝发,如:

class A

{

public:

? ? ? A(stirng s);

? ? ? A(string s,int a = 0);

};

class String?

{?

public:?

? ? String ( const char* p ); // 用C風格的字符串p作為初始化值?

? ? //…?

}?

String s1 = “hello”; //OK 隱式轉換,等價于String s1 = String(”hello”)苛谷,將char型變成了string類

隱式轉換二

使用operator what_you_want_to_convert_type() const

class A

? ? ? ? {

? ? ? ? public:

? ? ? ? ? ? ? ? operator char*() const

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? return data;//當從其他類型轉換到char*時自動調用

? ? ? ? ? ? ? ? }

? ? ? ? private:

? ? ? ? ? ? ? ? char* data;

? ? ? ? };

避免隱式類型轉換的方法:在單參數的構造函數或N個參數中有N-1個是默認參數的構造函數聲明之前加上explicit辅鲸。

C風格顯式轉換(C style explicit conversion)

要去掉上述waring很簡單,熟悉C語言的程序員知道腹殿,有兩種簡單的寫法(C風格轉換與函數風格轉換):

double a=2000.3;

short b;

b = (short) a;? ? // c-like cast notation

b = short (a);? ? // functional notation

// class type-casting

#include <iostream>

using namespace std;

class CDummy {

float i,j;

CDummy():i(100),j(10){}

};

class CAddition:public CDummy

{

? ? int *x,y;

? public:

? ? CAddition (int a, int b) { x=&a; y=b; }

? ? int result() { return *x+y;}

};

int main () {

? CDummy d;

? CAddition * padd;

? padd = (CAddition*) &d;

? cout << padd->result();

? return 0;

}


編譯器不報任何錯独悴,但運行結果出錯,

交流群728483370锣尉,一起學習加油~每天晚上群里面也會有大佬直播企業(yè)項目開發(fā)學習刻炒,更有各種項目案例供你自己學習哦!

此時父類的指針&d被C風格轉換方式強制轉成了子類的指針了,后面調用了子類的方法result自沧,需要訪問*x坟奥,但指針指向的對象本質還是父類的,所以x相當于父類中的i拇厢,y相當于父類中的j爱谁,*x相當于*i,但i是float型變量(初始化為100)孝偎,不是地址访敌,所以出錯,如果程序員正是魯莽地對這個地址指向的內存進行寫入操作衣盾,那將可能會破壞系統(tǒng)程序捐顷,導致操作系統(tǒng)崩潰荡陷!

這里有一個重要概念,CAddition*是子類的指針迅涮,它的變量padd可以調用子類的方法废赞,但是它指向的是父類的對象,也就是說padd指向的內存空間里存放的是父類的成員變量叮姑。深入地說唉地,數據在內存中是沒有“類型”一說的,比如0x3F可能是字符型传透,也可能是整型的一部分耘沼,還可能是地址的一部分。我們定義的變量類型朱盐,其實就是定義了數據應該“被看成什么”的方式群嗤。

因此padd類指針實質是定義了取值的方式,如padd->x就是一并取出內存空間里的0號單元至3號單元的值(共4個字節(jié))兵琳,將其拼成32位并當作指針狂秘,padd->y則取出內存空間里的4號單元至7號單元(共4個字節(jié)),將其拼成32位并當作int型變量躯肌。但實際上padd指向的是父類的對象者春,也就是前4個字節(jié)是float型變量,后4個字節(jié)也是float型變量清女。

從這里可以看出钱烟,程序員的這種轉換使編譯器“理解”出錯,把牛當成馬了嫡丙。

從上可見拴袭,用C風格的轉換其實是不安全的,編譯器無法看到轉換的不安全曙博。

上行轉換(up-casting)與下行轉換(down-casting)

看到這個拥刻,讀者可能會問,哪些轉換不安全羊瘩?根據前面所舉的例子,可以看到盼砍,不安全來源于兩個方面:其一是類型的窄化轉化尘吗,會導致數據位數的丟失;其二是在類繼承鏈中浇坐,將父類對象的地址(指針)強制轉化成子類的地址(指針)睬捶,這就是所謂的下行轉換〗酰“下”表示沿著繼承鏈向下走(向子類的方向走)擒贸。

類似地臀晃,上行轉換的“上”表示沿繼承鏈向上走(向父類的方向走)。

我們給出結論介劫,上行轉換一般是安全的徽惋,下行轉換很可能是不安全的。

為什么呢座韵?因為子類中包含父類险绘,所以上行轉換(只能調用父類的方法,引用父類的成員變量)一般是安全的誉碴。但父類中卻沒有子類的任何信息宦棺,而下行轉換會調用到子類的方法、引用子類的成員變量黔帕,這些父類都沒有代咸,所以很容易“指鹿為馬”或者干脆指向不存在的內存空間。

值得一說的是成黄,不安全的轉換不一定會導致程序出錯呐芥,比如一些窄化轉換在很多場合都會被頻繁地使用,前提是程序員足夠小心以防止數據溢出慨默;下行轉換關鍵看其“本質”是什么贩耐,比如一個父類指針指向子類,再將這個父類指針轉成子類指針厦取,這種下行轉換就不會有問題潮太。

針對類指針的問題,C++特別設計了更加細致的轉換方法虾攻,分別有:

static_cast <new_type> (expression)

dynamic_cast <new_type> (expression)

reinterpret_cast <new_type> (expression)

const_cast <new_type> (expression)

可以提升轉換的安全性铡买。

static_cast (expression) 靜態(tài)轉換

靜態(tài)轉換是最接近于C風格轉換,很多時候都需要程序員自身去判斷轉換是否安全霎箍。比如:

double d=3.14159265;

int i = static_cast(d)奇钞;

但static_cast已經有安全性的考慮了,比如對于不相關類指針之間的轉換漂坏。參見下面的例子:

// class type-casting

#include <iostream>

using namespace std;

class CDummy {

? ? float i,j;

};

class CAddition {

? ? int x,y;

? public:

? ? CAddition (int a, int b) { x=a; y=b; }

? ? int result() { return x+y;}

};

int main () {

? CDummy d;

? CAddition * padd;

? padd = (CAddition*) &d;

? cout << padd->result();

? return 0;

}

這個例子與之前舉的例子很像景埃,只是CAddition與CDummy類沒有任何關系了,但main()中C風格的轉換仍是允許的padd = (CAddition*) &d顶别,這樣的轉換沒有安全性可言谷徙。

如果在main()中使用static_cast,像這樣:

int main () {

? CDummy d;

? CAddition * padd;

? padd = static_cast<CAddition*> (&d);

? cout << padd->result();

? return 0;

}

編譯器就能看到這種不相關類指針轉換的不安全驯绎,報出錯誤完慧。注意這時不是以warning形式給出的,而直接是不可通過編譯的error剩失。從提示信息里可以看到屈尼,編譯器說如果需要這種強制轉換册着,要使用reinterpret_cast(稍候會說)或者C風格的兩種轉換。

總結一下:static_cast最接近于C風格轉換了脾歧,但在無關類的類指針之間轉換上甲捏,有安全性的提升。

dynamic_cast (expression) 動態(tài)轉換

動態(tài)轉換確保類指針的轉換是合適完整的涨椒,它有兩個重要的約束條件摊鸡,

要求new_type為指針或引用

下行轉換時要求基類是多態(tài)的(基類中包含至少一個虛函數)。

看一下下面的例子:

#include <iostream>

using namespace std;

class CBase { };

class CDerived: public CBase { };

int main()

{

CBase b; CBase* pb;

CDerived d; CDerived* pd;

pb = dynamic_cast<CBase*>(&d);? ? // ok: derived-to-base

pd = dynamic_cast<CDerived*>(&b);? // wrong: base-to-derived

}

在最后一行代碼有問題蚕冬,編譯器給的錯誤提示免猾,基類CBase不是vritual多態(tài)類型。

把類的定義改成:

class CBase { virtual void dummy() {} };

class CDerived: public CBase {};

再編譯囤热,結果編譯成功猎提。

我們看到一個奇怪的現象,將父類經過dynamic_cast轉成子類的指針竟然是空指針旁蔼!這正是dynamic_cast提升安全性的功能锨苏,dynamic_cast可以識別出不安全的下行轉換,但并不拋出異常棺聊,而是將轉換的結果設置成null(空指針)伞租。

再舉一個例子:

#include <iostream>

#include <exception>

using namespace std;

class CBase { virtual void dummy() {} };

class CDerived: public CBase { int a; };

int main () {

? try {

? ? CBase * pba = new CDerived;

? ? CBase * pbb = new CBase;

? ? CDerived * pd;

? ? pd = dynamic_cast<CDerived*>(pba);

? ? if (pd==0) cout << "Null pointer on first type-cast" << endl;

? ? pd = dynamic_cast<CDerived*>(pbb);

? ? if (pd==0) cout << "Null pointer on second type-cast" << endl;

? } catch (exception& e) {cout << "Exception: " << e.what();}

? return 0;

}


輸出結果是:Null pointer on second type-cast

兩個dynamic_cast都是下行轉換,第一個轉換是安全的限佩,因為指向對象的本質是子類葵诈,轉換的結果使子類指針指向子類,天經地義祟同;第二個轉換是不安全的作喘,因為指向對象的本質是父類,“指鹿為馬”或指向不存在的空間很可能發(fā)生晕城!

reinterpret_cast (expression) 重解釋轉換

這個轉換是最“不安全”的泞坦,兩個沒有任何關系的類指針之間轉換都可以用這個轉換實現

class A {};

class B {};

A * a = new A;

B * b = reinterpret_cast<B*>(a);//correct!

reinterpret_cast可以把整型數轉換成地址(指針),這種轉換在系統(tǒng)底層的操作砖顷,有極強的平臺依賴性贰锁,移植性不好。

它同樣要求new_type是指針或引用滤蝠,下面的例子是通不過編譯的:

double a=2000.3;

short b;

b = reinterpret_cast (a); //compile error!

const_cast (expression) 常量向非常量轉換

// const_cast

#include <iostream>

using namespace std;

void print (char * str)

{

? cout << str << endl;

}

int main () {

? const char * c = "sample text";

? char *cc = const_cast<char *> (c) ;

? Print(cc);

? return 0;

}

交流群728483370豌熄,一起學習加油~每天晚上群里面也會有大佬直播企業(yè)項目開發(fā)學習,更有各種項目案例供你自己學習哦!

從char *cc = const_cast<char *>(c)可以看出了這個轉換的作用了几睛,但切記房轿,這個轉換并不轉換原常量本身粤攒,即c還是常量所森,只是它返回的結果cc是非常量了囱持。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市焕济,隨后出現的幾起案子纷妆,更是在濱河造成了極大的恐慌,老刑警劉巖晴弃,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掩幢,死亡現場離奇詭異,居然都是意外死亡上鞠,警方通過查閱死者的電腦和手機际邻,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芍阎,“玉大人世曾,你說我怎么就攤上這事∏聪蹋” “怎么了轮听?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岭佳。 經常有香客問我血巍,道長,這世上最難降的妖魔是什么珊随? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任述寡,我火速辦了婚禮,結果婚禮上玫恳,老公的妹妹穿的比我還像新娘辨赐。我一直安慰自己,他們只是感情好京办,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布掀序。 她就那樣靜靜地躺著,像睡著了一般惭婿。 火紅的嫁衣襯著肌膚如雪不恭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天财饥,我揣著相機與錄音换吧,去河邊找鬼凶异。 笑死冒签,一個胖子當著我的面吹牛,可吹牛的內容都是我干的准谚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贯莺,長吁一口氣:“原來是場噩夢啊……” “哼风喇!你這毒婦竟也來了?” 一聲冷哼從身側響起缕探,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤魂莫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爹耗,有當地人在樹林里發(fā)現了一具尸體耙考,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年潭兽,在試婚紗的時候發(fā)現自己被綠了倦始。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡山卦,死狀恐怖楣号,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情怒坯,我是刑警寧澤炫狱,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站剔猿,受9級特大地震影響视译,放射性物質發(fā)生泄漏。R本人自食惡果不足惜归敬,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一酷含、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汪茧,春花似錦椅亚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扩灯,卻和暖如春媚赖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背珠插。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工惧磺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捻撑。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓磨隘,卻偏偏與公主長得像缤底,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子番捂,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容