0

以下のコード:

 public class Program
    {
        static void Main(string[] args)
        {
            father f = new son(); Console.WriteLine(f.GetType());
            f.show();
         }
    }

    public class father
    {
      virtual public void show()
        {
            Console.WriteLine("father");
        }
    }

    public class son : father
    {
        public override void  show()
        {
            Console.WriteLine("son");
        }
    }

結果は「son」です。' 'を''
に変更すると、結果は'父'になります。public override void show()public new void show()

だから私は以下の「ルール」を結論付けます:

  • 'override'を使用します。この関数が呼び出されるのは、実行時に決定されます。プログラムは、現在のオブジェクトの実際のタイプに応じて適切な関数を選択します(上記のように、fの実行時タイプはsonであるため、sonのショーを呼び出します)。
  • 'new'修飾子を使用すると、呼び出される関数はコンパイル時に決定されます。プログラムは、オブジェクトの宣言された型を選択してその関数を呼び出します(上記のように、fの宣言された型は父であるため、'new'修飾子を使用すると'father'を表示する出力。

上記のすべてが私がポリモーフィズムについて理解していることです。誤解や間違ったことはありますか?

4

4 に答える 4

5

'new'修飾子を使用すると、呼び出される関数はコンパイル時に決定されます。プログラムは、オブジェクトの宣言された型を選択してその関数を呼び出します(上記のように、fの宣言された型は父であるため、'new'修飾子を使用すると'father'を表示する出力。

あまり。決定は実行時に行われますが、メソッドは基本クラスの仮想メソッドをオーバーライドnewしません。これは、例をいくらか拡張することで最も簡単に示されます。

using System;

class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Base.Foo");
    }
}

class Derived : Base
{
    public override void Foo()
    {
        Console.WriteLine("Derived.Foo");
    }
}

class MoreDerived : Derived
{
    public new void Foo()
    {
        Console.WriteLine("MoreDerived.Foo");
    }
}

class Test
{
    static void Main()
    {
        Base x = new MoreDerived();
        x.Foo(); // Prints Derived.Foo
    }
}

ここでは、コンパイル時に、最もオーバーライドされた実装を呼び出すことが決定されます。たとえば、Base.Foo複数のFoo署名があった場合、どの署名を使用するかが決定されます。もちろん、どの実装が「最もオーバーライドされる」かは現時点では不明です。

実行時に、CLRは、ターゲットオブジェクトの実際のタイプ(である)に基づいて、最もオーバーライドされた実装を検出しますMoreDerived。しかしMoreDerived.Foo、オーバーライドしませんBase.Foo...一方Derived.Foo、オーバーライドするので、の実装Derivedは実際に実行されるものです。

于 2013-01-16T07:25:47.450 に答える
2

はい、それだけで機能します...あなたの理解は正しいです。

しかし、2番目のケースでは、 new intadを使用すると、override実際の実装、つまり親クラスの実装が非表示になります。

このメソッドを定義するために新しいキーワードが使用されたため、派生クラスのメソッドは呼び出されず、代わりに基本クラスのメソッドが呼び出されます。

MSDNからの例

// Define the base class
class Car
{
    public virtual void DescribeCar()
    {
        System.Console.WriteLine("Four wheels and an engine.");
    }
}

// Define the derived classes
class ConvertibleCar : Car
{
    public new virtual void DescribeCar()
    {
        base.DescribeCar();
        System.Console.WriteLine("A roof that opens up.");
    }
}

class Minivan : Car
{
    public override void DescribeCar()
    {
        base.DescribeCar();
        System.Console.WriteLine("Carries seven people.");
    }
}

クラスへの呼び出し

Car[] cars = new Car[3];
cars[0] = new Car();
cars[1] = new ConvertibleCar();
cars[2] = new Minivan();

出力

Car object: YourApplication.Car
Four wheels and an engine.
----------
Car object: YourApplication.ConvertibleCar
Four wheels and an engine.
----------
Car object: YourApplication.Minivan
Four wheels and an engine.
Carries seven people.
----------

その良い例を持っているMSDN:オーバーライドと新しいキーワードをいつ使用するかを知る(C#プログラミングガイド)

于 2013-01-16T07:17:23.077 に答える
2

'new'修飾子を使用すると、呼び出される関数はコンパイル時に決定されます。プログラムは、オブジェクトの宣言された型を選択してその関数を呼び出します(上記のように、fの宣言された型は父であるため、'new'修飾子を使用すると'father'を表示する出力。

これは少し間違っています。使用newとは、この関数が基本クラスの関数をオーバーライドしないことを意味します。関数のディスパッチは実行時に引き続き発生しますが、この関数は考慮されません。さらにテストする孫または娘のクラスがある場合、違いはより明確になります。

于 2013-01-16T07:18:32.330 に答える
1

通常のメソッドはクラスのタイプによって呼び出され、仮想メソッドはオブジェクトに割り当てられたメモリの内容によって呼び出されます。現在、キーワードnewは多態性の概念を隠し、そのタイプだけを気にします。

于 2013-01-16T07:25:28.863 に答える