2012-01-13 47 views
67

我已經看到了這兩個術語在各種網上的解釋幾乎可以互換使用,並且大多數課本我請教,也沒有有關的區別完全清楚。是什麼鑄造和脅迫的區別?

是否有可能解釋說,你們知道的差別清晰簡單的方式是什麼?

類型轉換(有時也被稱爲型鑄造

爲了在期望另一個上下文使用一種類型的值。

Nonconverting型投(有時也被稱爲型雙關語

不改變底層的比特改變。

脅迫

過程,通過該當由周圍的上下文要求第二類型編譯器自動將一種類型的值轉換成另一種類型的值。

+4

那麼[Wikipedia文章](http://en.wikipedia.org/wiki/Type_conversion)怎麼樣? – 2012-01-13 21:57:45

回答

83

Type Conversion

轉換指的是從一個數據類型或者隱含地或明確改變值到另一個,例如一個16位整數到一個32位整數。

脅迫用於表示的隱式轉換。

單詞轉換通常指的是顯式類型轉換(與隱式轉換相對),而不管這是重新解釋位模式還是實際轉換。

因此,強制是隱含的,強制轉換是明確的,並且轉換是其中的任何一種。


一些例子(從same source):

脅迫(隱式):

double d; 
int  i; 
if (d > i)  d = i; 

角色(顯式):

double da = 3.3; 
double db = 3.3; 
double dc = 3.4; 
int result = (int)da + (int)db + (int)dc; //result == 9 
+0

將本作「隱脅迫」多餘的? [這裏]的說明(http://www.postgresql.org/docs/8.4/static/functions-string.html)同時使用了「隱式強制」和「強制轉換」的時候你是不是 – 2015-12-04 19:40:41

+0

隱式轉換隻能做失去精確性或有意義(例如:Int - > double)。在大多數現代語言中,你不能做double-> int,因爲你會失去精度。通過類型強制,這不是一個「問題」。 – 2016-04-14 13:25:52

6

Casting是您將對象類型視爲另一類型的過程,Coercing將一個對象轉換爲另一個對象。

請注意,在前一個過程中不涉及任何轉換,您有一個類型,您希望將其視爲另一個類型,例如,您有3個不同的從基類型繼承的不同對象,並且您有一個方法將採取基本類型,在任何時候,如果你現在兒童的具體類型,你可以將它轉換爲它是什麼,使用所有的具體方法和對象的屬性,不會創建對象的新實例。

另一方面,脅迫意味着在新類型的內存中創建一個新對象,然後將原始類型複製到新類型中,將兩個對象留在內存中(直到垃圾收集器帶走, 或兩者)。

+1

一個例子有助於澄清你試圖做出的區別。 – 2012-01-13 21:58:43

+0

我雖然有關的例子,並與它相處的時候了;) – PedroC88 2012-01-13 22:01:22

1

下面是一個從0123發佈:

強制與鑄造之間的差異往往被忽視。我明白爲什麼;許多語言對這兩種操作都有相同(或相似)的語法和術語。一些語言甚至可以將任何轉換稱爲「轉換」,但以下解釋涉及CTS中的概念。

如果您試圖將某種類型的值分配給不同類型的位置,則可以生成與原始類型具有類似含義的新類型的值。這是脅迫。強制讓你使用新的類型創建一個新的值,在某種程度上類似於原始值。一些強制可能會丟棄數據(例如,將int 0x12345678轉換爲短0x5678),而其他強制可能不會(例如將int 0x00000008轉換爲短0x0008或長0x0000000000000008)。

回想一下值可以有多種類型。如果你的情況稍有不同,並且你只想選擇一個不同的值類型,那麼cast就是這個工作的工具。投射只是表示您希望使用某個值包含的特定類型進行操作。

代碼級別的差異從C#到IL不等。在C#中,無論是鑄造和脅迫看起來非常相似:

static void ChangeTypes(int number, System.IO.Stream stream) 
{ 
    long longNumber = number; 
    short shortNumber = (short)number; 

    IDisposable disposableStream = stream; 
    System.IO.FileStream fileStream = (System.IO.FileStream)stream; 
} 

在IL水平,他們有很大的不同:

ldarg.0 
conv.i8 
stloc.0 

ldarg.0 
conv.i2 
stloc.1 


ldarg.1 
stloc.2 

ldarg.1 
castclass [mscorlib]System.IO.FileStream 
stloc.3 

至於邏輯水平,有一些重要的區別。最重要的是要記住,強制創造了一個新的價值,而鑄造則沒有。原始值和鑄造後的值的標識是相同的,而被強制值的標識不同於原始值; coersion創建一個新的不同的實例,而cast不會。一個必然結果是,演員和原作的結果總是等同的(無論是身份還是平等),但是被強制的價值可能與原始價值相等,也可能不相同,也不會分享原始身份。

在上面的例子中很容易看到強制的含義,因爲數字類型總是按值複製。當您使用引用類型時,事情會變得更加棘手。

class Name : Tuple<string, string> 
{ 
    public Name(string first, string last) 
     : base(first, last) 
    { 
    } 

    public static implicit operator string[](Name name) 
    { 
     return new string[] { name.Item1, name.Item2 }; 
    } 
} 

在下面的例子中,一個轉換是一個轉換,而另一個轉換是強制轉換。

Tuple<string, string> tuple = name; 
string[] strings = name; 

經過這些轉換之後,元組和名稱是相等的,但字符串不等於它們中的任何一個。通過在Name類上實現Equals()和operator ==()來比較一個Name和一個字符串[],你可以使情況稍微好一些(或者稍微混淆一點)。這些操作員將「解決」比較問題,但您仍然有兩個單獨的實例;對字符串的任何修改都不會反映在名稱或元組中,而對名稱或元組中的任何一個的更改都會反映在名稱和元組中,而不是字符串中。

雖然上面的例子是爲了說明鑄造和脅迫之間存在一些差異,它也可以作爲爲什麼你應該約在C#中使用轉換操作符與引用類型極其謹慎的一個很好的例子。

20

用法不同,你注意。

我個人的用途是:

  • A 「投」 是轉換運算的使用。轉換運算符指示編譯器:(1)此表達式不是已知的給定類型,但我向您保證,該值在運行時將是該類型的;編譯器會將表達式視爲給定類型的表達式,如果不是,則運行時會產生錯誤,或者(2)表達式完全是不同的類型,但有一種衆所周知的方式來關聯實例表達式的類型與轉換類型的實例。指示編譯器生成執行轉換的代碼。細心的讀者會注意到這些是對立面,我認爲這是一個巧妙的把戲。

  • 「轉換」是一種操作,通過該操作,一種類型的值被視爲另一種類型的值 - 通常是不同的類型,儘管「身份轉換」在技術上仍然是轉換。轉換可能是「表示改變」,如int加倍,或者它可能是「表示保留」,如字符串到對象。轉換可能是「隱含的」,不需要轉換,或者「顯式」轉換,這需要轉換。

  • A 「脅迫」 是一個表徵改變隱式轉換。

+0

我認爲這個答案的第一句話是最重要的。不同的語言使用這些術語來表示完全不同的東西。例如,在Haskell中,「強制」*從不*改變表示;一個安全的強制,'Data.Coerce.coerce :: Coercible a b => a - > b'適用於被證明具有相同表示的類型; '不安全.Coerce.unsafeCoerce :: a - > b'適用於任何兩種類型(如果您錯誤地使用它,會使惡魔從鼻子裏冒出來)。 – dfeuer 2014-10-22 01:55:01

+0

@fefeuer有趣的數據點,謝謝!我注意到C#規範沒有定義「強制」;我的建議正是我個人的意思。鑑於這個詞的定義很差,我通常會避免這個詞。 – 2014-10-22 02:23:59