《C++ Primer中文版》(第4版)的5.12.6節介紹static_cast、const_cast、reinterpret_cast的用法:
1、static_cast,編譯器飲食執行的任何類型轉換都可以由static_cast顯示完成,如:
double d=97.0char c1=d;//warningchar c2=static_cast<char>(d);//ok
也就是說,static_cast可以把編譯器的warning關掉。當需要將一個較大的算數類型賦值給較小的類型時,使用static_cast強制轉換非常有用。
2、const_cast,添加或刪除const特性,如:
const int &val=13;int &ncref=const_cast<int>(&val);//刪除const特性int &cref=const_cast<const int&>(ncref);//添加const特性
注意,可以給const變數使用const_cast<const XXX>轉換,也可以給非const繼續使用const_cast<XXX>轉換,不會報錯。
const_cast只能用來添加或刪除const特性,不能作他用,否則編譯報錯,如:
const int &val=13;int &ncref=const_cast<int>(val);//error,不能將const int轉換成int
而此時換成static_cast編譯正常:
const int &val=13;const int &ncref=static_cast<int>(val);//ok
注意,在G++中,此時的ncref必須定義成const(因為static_cast在轉換時產生了一個臨時變數),否則報錯;
在VS2005中不用定義成const,不產生臨時對象,不報錯……
因為int和int&是不相同的類型:
用int轉換時,會產生int型臨時對象,該對象是編譯器對被轉換的記憶體空間按照某一規則進行的數值上的轉換,如將float轉換成int時,就是對float佔據的記憶體空間裡的資料進行的基於IEEE浮點數定義的規則上的轉換,0.0->0,1.0->1,2.5->2等。
用int&轉換時,不會產生任何臨時對象,完全是使用int類型強制解釋被轉換的記憶體空間,而不是基於數值上的轉換,同樣用float轉換成int舉例:
float 1.0在記憶體中儲存為: 符號位 階(指數) 尾數 0 01111111 00000000000000000000000 關於浮點數儲存可以參見有關標準。 轉化為int&後,資料就變為00111111100000000000000000000000 = 1065353216
3、interpret_cast通常為運算元的位元模式提供較低層次的重新解釋。
/*將float轉成int&是對原float變數所佔用記憶體空間的重新解釋(以int類型讀取float的二進位形式的資料)**由於這種轉換不會由編譯器自動完成,所以使用static_cast<int&>報錯**應該使用reinterpret_cast<int&>,**而static_cast<int>在此處相當於(int)fval,是基於IEEE的浮點數規範的轉換,保持了數值的一致性**/float fval=1.0f;cout<<"reinterpret_cast<int&>="<<reinterpret_cast<int&>(fval)//1065353216<<",static_cast<int>(dval)="<<static_cast<int>(fval)<<endl;//1
綜上,
1、static_cast只能用來完成編譯器能自動完成的或出現warning的類型轉換,將一個較大的算數類型賦值給較小的資料類型(double=>int,int=>char等),
或在相同大小的資料類型間轉換(int&=>int,double&=>double等)(在G++中,static_cast<int>時會產生臨時對象,static_cast<int&>時不會產生臨時對象;在VS2005中都不會產生臨時對象……)
但是,static_cast不會完成const到非const的轉換,也不會把一個float值所佔的記憶體空間當成int來操作(如static_cast<int&>(1.0f)),因為編譯器也不會這麼乾的!
2、const_cast僅用來添加或刪除const特性,而不能用於類型轉換,注意int和int&不是同一個類型!
3、reinterpret_cast用於二進位層次的重新解釋,如將float或double所佔的記憶體空間當成int來解釋,而不是基於IEEE浮點數定義規則上的轉換。
以上3種命名的強制類型轉換是C++語言規範的一部分,而不是C裡的,因為C++相容C,所以,C裡的強制類型轉換文法在C++中也適用:
const int &val=2;float fval=1.0f;//const_cast<int&>int &ncref1=(int&)(val);//okncref1=10;//int &ncref2=val;//error,不能將const變數賦值給非const引用cout<<"ncref1="<<ncref1<<",val="<<val<<endl;//static_cast<int>int ival1=(int)fval;//okint ival2=fval;//ok,float與int位元相等;如果將double賦值給int,則出現warning//reinterpret_cast<int&>int &iref1=(int&)fval;cout<<"iref1="<<iref1<<endl;//static_cast<int>const int &iref2=(int)fval;//由於返回的是臨時int變數,所以必須使用const修飾cout<<"iref2="<<iref2<<endl;
上面代碼中,關於const_cast的程式碼片段,如果修改成:
const int val=2;//const_cast<int>int &ncref1=(int&)(val);//ok,VS2005中偶爾運行時報錯,G++中編譯運行都不報錯//上式等價於int &ncref1=const_cast<int&>(static_cast<const int&>(val));ncref1=10;//ncref1=10,val=2cout<<"ncref1="<<ncref1<<",val="<<val<<endl;
則得不到預期的效果:ncref1=10,val=10,因為val被聲明為const,就無法改變它的值。注意之前用const_cast刪除const特性的例子,用的都是引用(int&),有什麼區別呢?
const int & val=2;表示我分配了一個int變數的空間,這個空間沒有名字,其值為2,然後我用val這個名字來指代這個空間,由於我在定義這個名字的時候,用了const定義,所以,我不能通過這個這個名字(val)去修改對應記憶體空間的值。但是,我可以通過別的名字來修改這個記憶體空間的值,只要將val的地址告訴別的引用或者指標就行了!
const int val=2;表示我分配了一個int變數的空間,這個空間的名字叫val,而且這個空間是const的,不能通過這個名字(val)或其他任何名字來修改這個記憶體空間的值!
參考資料:
1、C/C++左值性精髓(二)哪些運算式是左值,哪些是右值?--- 函數調用運算式和強制轉換
2、一道C++的題目 關於(int)與(int &)
3、(int)a、&a、(int)&a、(int&)a的區別
附上剩餘實驗代碼:
void test(){const char *pc_str="hello";char *pc=(char*)(pc_str);//pc[0]='w';//error,不可以賦值,因為pc[0]指向的畢竟是常量欄位區("hello")int i=13;int j=13;int k=13;const int &val=13;//用常量給const引用賦值時,應該是分配了變數儲存空間const int &cref=val;/*(int&)val是將val的記憶體空間直接按照int型讀取(不進行數值上的轉換,不可以完成float到int的數值上的轉換)**(int)val是將val的記憶體空間裡的資料按照IEEE規則轉換數值(如可以完成float到int在數值上的轉換)**參見:**http://topic.csdn.net/u/20070618/15/64bf9e83-c422-43aa-a451-5deed812e947.html**和**http://talentluke.iteye.com/blog/789841**/int &ncref1=(int&)val;int &ncref2=const_cast<int&>(val);//const_cast<const int&>(val);//可以將const轉換成const;同理,也可以將非const轉換成非const//這個轉換應該使用const_cast完成//int &ncref3=static_cast<int&>(val);//error,static_cast只能做編譯器預設進行的轉換//在下面兩句話中,(int)與static_cast<int>功能相同//int &ncref4=(int)val;//在VS2005中ok;在G++中error,因為(int)強轉時,產生了臨時變數,是const型的//int &ncref5=static_cast<int>(val);//在VS2005中ok;在G++中error,原因同上//int &ncref6=const_cast<int>(val);//error,const_cast只能增/刪const屬性,不能轉換類型(int&轉int)//int &ncref7=static_cast<int&>(val);//error,不能把const int&轉換成int//int &ncref8=val;//error,不能把const int&轉換成int&cout<<&i<<","<<&j<<","<<&k<<","<<&val<<","<<&cref<<","<<&ncref2<<endl;cout<<"初始值:"<<endl;cout<<"i="<<i<<",val="<<val<<",cref="<<cref<<",ncref1="<<ncref1<<",ncref2="<<ncref2<<endl;/*數值都被改變**C++中的const屬性只是限制程式通過const變數修改某記憶體空間,**但是可以通過其他非const變數修改這塊記憶體空間**/ncref2=10;cout<<"結果值:"<<endl;cout<<"i="<<i<<",val="<<val<<",cref="<<cref<<",ncref1="<<ncref1<<",ncref2="<<ncref2<<endl;/*將float轉成int&是對原float變數所佔用記憶體空間的重新解釋(以int類型讀取float的二進位形式的資料)**由於這種轉換不會由編譯器自動完成,所以使用static_cast<int&>報錯**應該使用reinterpret_cast<int&>,**而static_cast<int>在此處相當於(int)fval,是基於IEEE的浮點數規範的轉換,保持了數值的一致性**/float fval=1.0f;cout<<"reinterpret_cast<int&>="<<reinterpret_cast<int&>(fval)<<",static_cast<int>(dval)="<<static_cast<int>(fval)<<endl;}int _tmain(int argc, _TCHAR* argv[]){int i(1);test();cin>>i;return 0;}