計算機程式設計/型別轉換
在計算機科學中,型別轉換或型別強制轉換是指將一個資料型別的值轉換為另一個數據型別。轉換有兩種型別:隱式和顯式。隱式型別轉換被稱為強制轉換。顯式型別轉換以某種特定方式被稱為強制轉換。顯式型別轉換也可以透過單獨定義的轉換例程來實現,例如過載的類建構函式。
隱式型別轉換,也稱為強制轉換,是由編譯器自動完成的型別轉換。一些語言允許甚至要求編譯器提供強制轉換。
在混合型別表示式中,一個子型別s將被轉換為一個超型別t,或一些子型別s1、s2、... 將被轉換為一個超型別t(可能沒有si是型別t),在執行時,以確保程式能夠正確執行。例如
double d;
long l;
int i;
if (d > i) d = i;
if (i > l) l = i;
if (d == l) d *= 2;
在C語言程式中是合法的。雖然d、l和i屬於不同的資料型別,但在每次執行比較或賦值時,它們將被自動轉換為相同的資料型別。
顯式轉換有幾種型別。
- 檢查式
- 在執行轉換之前,會進行執行時檢查以檢視目標型別是否能夠實際容納源值。如果不能,則會引發錯誤條件。
- 非檢查式
- 不會執行任何檢查,如果目標型別不能容納源值,則結果將是未定義的。
- 位模式
- 資料不會被解釋,只會複製原始位模式。
每種程式語言都有自己的規則來規定如何轉換型別。通常,物件和基本資料型別都可以被轉換。
強制轉換,或顯式型別轉換,是一種特殊的程式設計指令,它指定在給定表示式中將變數(或中間計算結果)視為哪種資料型別。
強制轉換將忽略“額外”的資訊(但永遠不會向被轉換的型別新增資訊)。C/C++強制轉換是“非檢查式”或“位模式”。
以基本資料型別為例,一個定點浮點數可以被強制轉換為一個整數,其中小數點(或二進位制點)後的資料將被忽略。或者,一個整數可以被強制轉換為一個浮點數,例如,如果一個函式呼叫需要一個浮點型別(但如前所述,實際上不會新增任何資訊,1 將變成 1.0000000)。
物件強制轉換的工作方式類似。一個子類可以被強制轉換為一個父型別,其中使它成為子類的“額外”資訊將被忽略,只處理從父類繼承的部分。例如,從形狀類派生的三角形類可以被強制轉換為形狀。
有兩種常見的轉換方式,如下所示。
這種轉換方式在C和Java中使用。它遵循以下形式
(type)expression
在C++中使用了多種轉換語法(雖然也支援C風格轉換)。函式呼叫風格遵循以下形式
type(expression)
這種轉換方式被採用是為了在使用轉換時強制清晰。例如,C風格轉換的
(type)firstVariable + secondVariable
的結果和意圖可能不清楚,而使用C++風格轉換的相同轉換可以使意圖更加清晰
type(firstVariable + secondVariable)
或
type(firstVariable) + secondVariable
在C++的演變過程中,為了進一步明確程式設計師的意圖,添加了以下更明確的轉換方式
static_cast<type>(value_to_cast)
dynamic_cast<type>(value_to_cast)
const_cast<type>(value_to_cast)reinterpret_cast<type>(value_to_cast)
靜態轉換將型別相容的值進行轉換。例如,以下示例
double myDouble = 3.0;
int myInt = static_cast<int>(myDouble);
將雙精度浮點數值myDouble(3.0)轉換為相應的整數值(3)。靜態轉換可能很危險
YourClass * pYour = GimmeAnObject();
void * pv = pYour; // no cast needed.
MyClass * p = static_cast<MyClass *>(pYour); // MyClass had better be related to YourClass...
p->SomeMethod(); // ...or this might blow up in a nasty way.
對指標或引用的靜態轉換不會驗證指向的物件是否與新型別相容。
在這種情況下,動態轉換比靜態轉換更安全:它由編譯器編譯成對C++執行時庫的呼叫,在那裡會進行檢查以確保轉換合法。這類似於Java中的轉換。
YourClass * pYour = GimmeAnObject();
void * pv = pYour; // no cast needed.
MyClass * p = dynamic_cast<MyClass *>(pYour); // This will not blow up in the same way
if (p != 0)
p->SomeMethod(); // C++ guarantees p points to a MyClass
對指標的動態轉換如果轉換值型別不相容,則返回空指標。對引用的動態轉換會丟擲一個型別異常。
const轉換將消除物件的const屬性,返回對同一物件的非const引用。這允許對通常由編譯器視為只讀的物件進行修改
const MyClass * cantTouchThis = CreateConstObject();
cantTouchThis->constant_value = 41; // compile-time error.
const_cast<MyClass *>(cantTouchThis)->constant_value = 42; // compiles, but who knows what happens at runtime?
重新解釋轉換是C++中最臭名昭著的一個。它允許重新解釋值的原始位模式,完全忽略型別系統。例如,它允許將任意整數強制轉換為指向物件的指標
MyClass * pclass = reinterpret_cast<MyClass *>(0xDEADBEEF); // I know what I am doing
pclass->some_field = 3.14159; // very unsafe indeed
//Using Converting of Type casting
Console.WriteLine("\nUsing Converting of Type casting");
string U = "10000000";
int V = Convert.ToInt32(U);
Console.WriteLine("\nHinger value={0} and Lower value ={1}", U, V);
當這些冗長的轉換被引入到語言中時,意見分歧。反對者認為新的語法很“醜”,而支持者認為,由於轉換本身就是一個“醜陋”的活動,所以應該用一個“醜陋”的語法來突出顯示它,以提醒程式設計師。另一個被認為的優勢是,使用像grep這樣的程式設計工具,很容易在原始碼中找到冗長的轉換。