クラス (インスタンスではなく) を見ると、次のように絵を描くことになります。
つまり、Dog
クラスには通常、クラスよりも多くのメソッドとプロパティがありAnimal
ます (たとえば、犬にはbark
(メソッド) があり、4 つのlegs
(プロパティ) があります)。そしてもちろん、このクラスをインスタンス化するときに、追加のメモリを予約する必要があります。基本クラスのメソッドとプロパティが最初に作成され、次に派生メソッドとプロパティがメモリ内に作成されると想像してください。
class Dog : Animal
{
public Dog()
{
legs = 4;
Console.WriteLine("Dog constructor");
}
public int legs { get; private set; }
public void bark()
{
Console.WriteLine("grrrwoof!");
}
}
をインスタンス化し、それを参照変数Dog
に割り当てた場合、この参照はが持つメソッドにのみアクセスできます。この事実にもかかわらず、オブジェクト全体はまだメモリに保持されています。Animal
Animal
Dog
Dog d = new Dog();
Animal a = (Animal)d;
つまり、d
次のことができます。
Console.WriteLine(String.Format("Number of legs: {0}", d.legs.ToString()));
d.bark();
これらの「機能」はクラスa
内で定義されていないため、それはできません。Animal
ここで知っておくべき重要なことは、すべての種類のキャストが許可されているわけではないということです。これは安全であるため、常に aDog
から anにキャストできますが、 anを a に暗黙的にAnimal
キャストすることはできないため、次のコードは無効なキャスト例外をスローします。Animal
Dog
Dog dogRef2 = a; // not allowed
何をしているのかわかっている場合 (つまり、a
に のインスタンスが含まれていることが確実にわかっている場合Dog
)、次のように明示的にキャストできます。
Dog dogRef2 = (Dog)a; // allowed
その後、プロパティとメソッドにアクセスできます。
dogRef2.bark(); // works
これが機能するのは、コンパイラとランタイムが常に同じ構造化された方法でメソッドとプロパティをメモリに格納し、参照時にそれを見つけるための内部記述子も作成するためです。
たとえば、次のことを試した場合、これは常に安全であるとは限らないことに注意してください。
Animal a = new Animal();
Dog dogRef2 = (Dog)a; // Invalid cast exception
なんで?new Animal()
methodbark
と property を作成していないため、 ( propertyも method も含まない)legs
のインスタンスを作成しただけです。Animal
legs
bark
詳細情報:内部構造 (オブジェクトの作成方法と保存方法) について詳しく知りたい場合は、このリンクを確認してください。そこから取ったメモリレイアウトの例を次に示します。
リンクされたリストを使用して、基本クラスのインスタンス オブジェクトから派生クラスのインスタンス オブジェクトへのチェーンを構築していることがわかります。