3

言う

class Animal
{
  public Animal()
   {
      Console.WriteLine("Animal constructor");
   }
}

class Dog : Animal
{
public Dog()
   {
      Console.WriteLine("Dog constructor");
   }
   }

このようなコードを書くと、ここで問題が発生します

Animal A = new Animal();

オブジェクトがヒープ内に作成され、参照変数「A」がヒープ内のその場所を指します。

今、このようなコードを書くと

Animal B = new Dog();

では、参照 B はどのようにして対象の犬を指すのでしょうか?

私はこの概念の視覚的なイラストにこだわっています。「動物型のオブジェクトがありますが、それは犬型のオブジェクトを参照しています」と何度も読みました。しかし、それは本当にどういう意味ですか?

どんな精巧な答えでもいいでしょう。私は .net (OOPS) の概念を深く学んでいません。

動物と犬のオブジェ

4

4 に答える 4

2

参照 B はどのようにして対象の犬を指していますか?

同様に、参照 A はオブジェクト Animal を指します。継承とインスタンス化を介してクラスがどのように関連付けられているかを混乱させていると思います。

別のクラスから派生したクラスの新しいインスタンスを作成しても、その基本クラスのインスタンスへの参照はありません。

Animal a = new Animal();
Animal b = new Dog();

Animal bには への参照もリンクもありません。それらはタイプ のAnimal a2 つの別個のインスタンスAnimalです。違いはAnimal b、実際には is 型Dogですが、としてキャストされていAnimalます。継承階層を上下にキャストしても、参照は変更されません (これを表す専門用語は参照変換と呼ばれます)。

Dog d = (Dog)b;

は同じオブジェクトを参照しますが、参照のタイプAnimal bが異なるだけです。

于 2012-08-27T09:55:37.190 に答える
1
class Animal
{
    public Animal() 
    { 
        Console.WriteLine("Animal constructor"); 
    }

    public  void  show()        
    {
        Console.WriteLine("animal");
    }

}

class Dog : Animal 
{ 
    public Dog() 
    { 
        Console.WriteLine("Dog constructor"); 
    }

    public  void show()
    {
        Console.WriteLine("Dog");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal B = new Dog();

        B.show();
        Console.ReadKey();
    }
}

上記プログラムでは

B.show();

基本クラスを呼び出しますshow()

なぜ、なぜなら、メソッドDog()も持つことになるため、使用される参照型が Animal だったので、これが呼び出されます。 Dog のクラスshow()を引き続き呼び出したい場合は、仮想およびオーバーライドの概念を使用show()

于 2012-08-27T10:52:57.183 に答える
1

クラス (インスタンスではなく) を見ると、次のように絵を描くことになります。

ここに画像の説明を入力

つまり、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に割り当てた場合、この参照はが持つメソッドにのみアクセスできます。この事実にもかかわらず、オブジェクト全体はまだメモリに保持されています。AnimalAnimalDog

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キャストすることはできないため、次のコードは無効なキャスト例外をスローします。AnimalDog

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のインスタンスを作成しただけです。Animallegsbark

詳細情報:内部構造 (オブジェクトの作成方法と保存方法) について詳しく知りたい場合は、このリンクを確認してください。そこから取ったメモリレイアウトの例を次に示します。 EEクラス

リンクされたリストを使用して、基本クラスのインスタンス オブジェクトから派生クラスのインスタンス オブジェクトへのチェーンを構築していることがわかります。

于 2012-08-27T10:58:58.727 に答える
0

動物 B = new Dog();

new 演算子は Dog() の参照を返します。これは Animal B に格納されるため、参照 b は犬を指しています

于 2012-08-27T10:17:47.623 に答える