文章目錄
- 強型別與弱類型語言
- 隱式轉換
- 新式強制類型轉換方式
- C#強制類型轉換
強型別與弱類型語言
像C++,C,Java,C#這些主流的程式設計語言都是強型別語言.而一些指令碼語言則是弱類型的,比如vbscript , javascript.
1.強型別語言簡單的理解就是當定義了一個變數之後就會指定一個固定的類型,並對應一個固定的記憶體塊大小.比如有int , double ,long這一個個的類型.並且一旦一個變數被指定為某個類型後就不能被當成其他類型用.除非做轉換
在C++中我們經常看到int ,long之類的數實值型別之間貌似可以互相通用.實際上是編譯器按照實際情況給你隱式的做了下轉換.而如果你把指標類型賦值給整數類型的話不符合通常的習慣,所以編譯器就不給轉了,直接報錯.
2.弱類型語言可以簡單的理解成沒有劃分成int,float,char這多麼類別.根本沒類型的概念.以前我們數學中用變數x,y一樣,它就相當於一個代表符號,預留位置一樣,可以表示任何類型.像javascrip中我們在任何變數前簡單的加個var就行.比如var pos = 123; pos =
"I change"; 有些指令碼語言乾脆就不需要用var這樣的東東來指定,直接 x = 3.14; y = "i am god"; 隨便整個標識符放等號左邊就是變數了.這樣做基於的原理是所有資料在記憶體中無非都是表示成0101,我想怎麼去解釋這些01就怎麼翻譯,才不用你編譯器來限制我啊.不過實際上要完全沒類型的概念也不行,比如a = 1 + "3";怎麼去辨別3是當成數字還是字串.所以弱類型語言背後的解譯器肯定會去做些類別判斷,做些轉換的.只是我們用起來看不到而已了.
弱類型語言使用起來非常靈活,方便.但如果代碼一多肯定容易出錯.而強型別雖然沒那和靈活,但型別安全了嘛.不容易出錯.而且編譯器也會做類型檢查,在編譯期間發現一些類型使用不當的地方就給你報錯.
弱類型語言由於根本沒區分那麼多類型.所以自然不存在啥類型轉換.強型別語言為了不完全丟掉弱類型語言的靈活性,也允許不同類型之間做些轉換.有時會隱式的轉換.但最好還是盡量強制的去轉換好點.
隱式轉換
在隱式類型轉換中,C++的判斷條件松一點,幾乎所有的數實值型別之間都可以給你隱式轉換了.比如int ,float , char之間都可以互相轉,不會去檢查啥值溢出或精度損失.而C#隱式轉換條件嚴格很多.只有當沒有值溢出且沒有精度損失時才給轉,不然報錯.
比如 double dd = 12.12;
int num = dd; //把dd隱式轉換成int類型
這在c++中可以正常轉換.但在C#中會報錯的.C#中必須要自己去顯式轉換才行.
強制類型轉換(顯式轉換)
強制類型轉換和顯式類型轉換是一會事,文字遊戲,說法不一樣而已.
舊式的強制類型轉換
C語言中的類型轉換方式很簡單.例如所float轉換成int就是這樣
double dd= 12.12;
int num = (int) dd; //或者int num = int(dd);
反正就在某個變數前加個類型名,然後用括弧括下就可以了.
C++中繼續相容了C的用法.但C#只沿用了上面兩種用法的前一種,就是int num = (int) dd;但int num = int(dd)這種用法沒有再沿用,如果你這樣用了編譯器會報錯的.
舊式用法雖然簡單方便,但也有些缺點,比如如果是一連串的運算式中,有很多個括弧,這樣就不容易看出是類型轉換了,可視性較差.而且沒有錯誤處理機制.於是C++和C#都弄出了新的轉換方法.
新式強制類型轉換方式
C++中有static_cast , dynamic_cast, const_cast, 和reinterpret_cast四種轉換方式.
你可能初次瞧到這麼多關鍵字,而且長得這長醜一個,肯定看得非常不順眼,會覺得還是C語言中加個括弧簡單方便美觀多了. C++這四種轉換方式有一個說法(當然真實性我還不確定)是其實是故意弄的樣子這麼醜而且是4個這麼多,目的就是為了讓你用的不方便,最後都不想去用.因為強型別語言之所以整出那麼多類型出來就是為了讓你老實的按規矩用,別閑著沒事轉來轉去.除非特殊情況非用不可才去轉換.
1.const_cast
這個轉換方式的功能只有一個,就是把const類型轉換成非const類型.這種轉換隻能用這一種方法,其他三種方法用來幹事就會出錯.
你可能糊塗了,我們定義const的目的就是為了不讓修飾那變數,怎麼又要轉成非const的了.大部分時候我們自然不會閑得蛋痛去做這樣的轉換,只有一些特殊情況會用到.比如你有這樣的指標const char* pc = "arwen";
但是有個函數非要你轉個char* 參數進去.比如Fun(char* pc),於是沒轍啊,只能把轉成非const.於是就這樣轉
Fun( const_cast<char*> (pc) );
當然了實際上你要用老式的方法也一樣達到目的Fun ( (char*) pc );
再比如如下例子
int num = 44;
const int* pNum = #
//*pNum = 88;這樣肯定會報錯
//int* ip = pNum;這樣用也不行.
int* ip = const_cast<int*> ( pNum); //ok,等價於int* ip = (int*) pNum;
*ip = 88;
cout<<num; //結果為88
2.reinterpret_cast
它一般用來轉換不同類型的指標轉換,或者在指標和數值之間轉換.例如
int num = 123;
int* pNum = #
char* pChar = "weiwen";
pNum = reinterpret_cast<int*>( pChar); //把char指標轉換成int*.
int no = reinterpret_cast<int> (pChar); //把指標轉換成整數數字
char* pc = reinterpret_cast<char*> (no); //把數字轉換成char*指標
當然上面的所有轉換也可以用老方法 比如(int*) pChar, (int)pChar這樣,簡單的用個括弧就行. 完全等價的.
3.dynamic_cast
一般用於繼承間類型的轉換.假如類Son 繼承自Father;
Fun(Father* fa)
{
Son* so = dynamic_cast<Son*>( fa );
}
1)假如Father中沒有虛函數,則上面的代碼編譯時間會報錯.如果有這樣的情境你實在要用的話就只能用Son* so = (Son*) fa; //不會報錯.
2)當然如果Father和Son沒有繼承關係的話,上面轉換的結果就是so得到一個null指標.如果用Son* so = (Son*) fa;即使沒繼承關係也能成功轉換,只不過這樣得到的指標如果運用它肯定容易有很多錯誤.
4.static_cast
這種用法是最簡單也最容易理解的,因為隱式轉換時實際上都調用的它.所以一般認為合理的轉換就用它,比如各種數值之間轉換.而不合理的轉換比如要把char* 類型轉換成int*就會出錯.同樣也可以用老式方法替代了.
另外如果Son繼承自Father,而Father沒有虛函數,此時不能通過dynamic_cast了,但可用static_cast,例如Son* so = static_cast<Son*>(fa);
C#強制類型轉換
C#中有個關鍵字as,如果轉換不成功就返回null;這主要用於自訂類型,各種對象之間的轉換
比如 Son so = fa as Son;
另外內建類型的轉換一般用函數Convert
比如有float類型ff.轉成int型
int num = Convert.ToInt32(ff);
如果是把string類型轉換成數實值型別可用函數Parse
比如int num = int.Parse("123");