2016-10-28 12 views
0

MSDNで参照型の場合、基本型から派生型に変換する必要がある場合は明示的キャストが必要です。C#の参照型のメモリに関する明示的なキャストの説明

"プログラミング言語理論では、参照型はメモリのオブジェクトを参照するデータ型です。一方、ポインタ型はメモリアドレスを参照します。参照型は次のように考えることができます。暗黙的に逆参照されるポインタ " Cでのケースです。

C#で参照型の明示的キャストを考慮した場合のメモリ格納手順の説明方法は?

+4

オブジェクトは、オブジェクトへの参照とは独立してメモリに格納されます。キャストは、オブジェクトを特定の型として扱う参照を取得するために使用されます。 [同じMSDNページから](https://msdn.microsoft.com/en-us/library/ms173105.aspx): "参照型間のキャスト操作では、実行時の型が変更されません。そのオブジェクトへの参照として使用されている値の型だけを変更します。 – apk

+0

この質問では 'C#'について議論しているので、 'C'と' C++ 'というタグを削除する必要があります – user3629249

答えて

1

ほとんどの場合、参照変数とポインタ変数の違いはあまりありません。どちらもメモリ内の場所を指しています。参照(またはポインタ)変数の型は、それを使用して実行できる操作をコンパイラに指示します。

基本的な型(intやbyteなど)で(主に)使用されるCポインタの代わりに、C++オブジェクトポインタが最初に検討されます。それは本当にC#でとほぼ同じです:C#1に1、そう参照型だけで定義された型とポインタ(ビューのプログラマの観点から)です:

MyBaseClass* a = new MyBaseclass(); 
a->BaseMethod(); // Call method using -> operator (dereference and call) 

MyBaseClass* b = new MyDerivedClass(); 
b->DerivedMethod(); // Error: MyBaseClass has no such method 

// Proper C++-Style casting. 
MyDerivedClass* c = dynamic_cast<MyDerivedClass*>(b); 
// Shortcut to the above, does not do the type test. 
// MyDerivedClass* c = (MyDerivedClass*)b; 
c->DerivedMethod(); // Ok 

これは、ほぼ1を変換します。目に見える違いは、C#の直接CスタイルのキャストがC++のtry_castと同等であるため、間違ったターゲットインスタンスを決して参照変数に割り当てることができないことです。

ので、参照型とオブジェクトへのポインタとの違いは、(これらのほとんどはC#は、管理言語であるという事実によって暗示されている)、次のとおりです。

  • 参照変数無効なメモリを指すことはできません(NULLを除く)。
  • 参照変数は、その型ではないオブジェクトを指すことはできません。
  • 参照変数に値を割り当てる場合、その型は常にテストされます。
  • 参照変数へのキャストは、対象オブジェクトが指定された型であることを確認する必要があります。
1

参照オブジェクトは、コードから参照できるヒープに格納されます。オブジェクトは、ヒープ上にあるように、与えられた型のオブジェクトです。

コードから、参照を作成できます。これらの参照は、他のいくつかの型にキャストできます。

ここでは、2つのケースがあります。これについては、参照先の記事で説明しています。そこからの例を使用して簡単にします。あなたは、コードで特異的にそれを求めるないとき

1.暗黙的な変換

暗黙的な変換は、行われます。コンパイラはこれをどうやって行うのかを知る必要があります。

1.1。値のタイプ

キャストしようとしている値の型がサイズの場合、キャストする型のサイズを決定するメモリのサイズに格納できます。あなたはそれをする。これは、数値のほとんどがあるので、あなたの論文からの例を次に示します。intは長いよりも「小さい」ですので、だから、

// Implicit conversion. num long can 
// hold any value an int can hold, and more! 
int num = 2147483647; 
long bigNum = num; 

は、コンパイラは、あなたがこれを行うようになります。

1.2。あなたはクラスの定義を以下していると仮定すると、参照型

class Base {  

} 

class Derived : Base { 
    public int IntProperty { get; set; } 
    public int CalculateSomething() 
    { 
     return IntProperty * 23; 
    } 
} 

は、その後、あなたが安全のような変換を行うことができます。

Derived d = new Derived(); 
Base b = d; 

をこれは、ヒープ上に作成したので、オブジェクトd、です、 Derivedのタイプであり、タイプBaseの派生タイプであるため、Baseのメンバーがすべて含まれていることが保証されています。したがって、参照を変換してDerivedオブジェクトをBaseオブジェクトとして使用することは安全です。 派生ISベースDerived : Base)です。

2.明示的な変換

のは、我々は我々のプロジェクトに別のクラスを持っていると仮定しましょう:

class DerivedLike 
{ 
    public int IntProp { get; set; } 
    public int CalculateSomethingElse() 
    { 
     return IntProp * 23; 
    } 
} 

我々は

DerivedLike dl = new DerivedLike(); 
Derived d = dl; 

を記述する場合、我々はそれことを私たちのコンパイラから取得します暗黙的にタイプDerivedLikeDerivedに変換することはできません。

これは、2つの参照型が完全に異なるため、コンパイラはこれを許可しないためです。これらの型は異なるプロパティとメソッドを持っています。

2.1。明示的変換を実装する

派生クラスから基本クラスに自分で変換できない限り、ほとんどの場合、演算子を書くことができます。

DerivedLikeからDerivedへの変換を進めたい場合は、DerivedLikeクラスに変換演算子を実装する必要があります。あるタイプを別のタイプに変換する方法を示す静的演算子です。変換演算子は、暗黙的でも明示的でもよい。明示的には、開発者は、型名をかっこで指定することによって明示的にキャストする必要があります。

暗黙的オペレータと明示的オペレータのどちらを選択するかは、変換が例外をスローする可能性がある場合は、明示的にする必要があるため、変換が開発者によって意識的に行われるようにする必要があります。

のは、その要件を満たすために我々のコードを変更してみましょう:

class DerivedLike 
{ 
    public static explicit operator Derived(DerivedLike a) 
    { 
     return new Derived() { IntProperty = a.IntProp}; 
    } 
    public int IntProp { get; set; } 
    public int CalculateSomethingElse() 
    { 
     return IntProp * 23; 
    } 
} 

は、これは今も元気にコンパイルされます:メモリのトピックに戻って

DerivedLike dl = new DerivedLike(); 
Derived d = (Derived)dl; 

は、なるように変換して、あなたがなりますので、ご注意くださいヒープに2つのオブジェクトが追加されました。

ここで作成

ワン:ここで作成

DerivedLike dl = new DerivedLike(); 

第二1:

Derived d = (Derived)dl; 

は、ヒープ上のオブジェクトは、それの種類を変更することはできません。

これは明らかです。

関連する問題