-1
class A {
    public virtual void M() { Console.Write("A"); }
}

class B: A {
    public override void M() { Console.Write("B"); }
}

class C: B {
    new public virtual void M() { Console.Write("C"); }
}

class D: C {
    public override void M() { Console.Write("D"); }
    static void Main() {
        D d = new D(); 
        C c = d; 
        B b = c; 
        A a = b;
        d.M(); c.M(); b.M(); a.M();
    }
}

私はこの概念に慣れていないので、詳細な回答をいただければ幸いです。

4

2 に答える 2

5

修飾子はnew基本的に、同じ名前の新しいメソッドを作成し、同じ名前の基本メソッドを隠します。基本メソッドはまだそこにあり、隠されているだけです。基本型にキャストするだけで、クラスの外部から呼び出すことができます。ドキュメントから:

newキーワードを修飾子として使用すると、基底クラスから継承されたメンバーが明示的に非表示になります。

一方、overrideキーワードは、基本メソッドがサブクラスでオーバーライドされることを示します。オーバーライドされたインターフェイスを経由せずに基本メソッドを呼び出す方法はありません。

したがって、あなたの例では、b.M()あなたa.M()が呼び出してMメソッドを呼び出しているときB(これはから継承され、オーバーライドされAます)。一方、onという名前の完全に異なるメソッドを呼び出している場合d.M()(これは から継承およびオーバーライドされます)。c.M()MDC

于 2013-05-29T22:43:57.113 に答える
1

仮想メソッドを定義すると、継承ツリーのある時点でそのメソッドをオーバーライドできるようになります。あなたの例のような子孫クラスBは、何らかの方法でメソッドのロジックを変更できます。仮想メソッドの呼び出しでは、インスタンスを保持する変数の型ではなく、オブジェクト インスタンスの具体的な型に応じて、最も派生したオーバーライドが使用されます。

仮想メソッド テーブル (VMT) を使用して、これらの仮想メソッドと適用されたオーバーライドを追跡します。タイプの変数はA、クラスから派生した任意のクラスを保持できAます。この例では、、、AまたはのBいずれかです。VMT は、仮想メソッドを呼び出すときに呼び出すオーバーライド メソッドを決定するために使用されます。したがって、あなたの例では、メソッドをオーバーライドします。メソッドを呼び出すと、プログラムは呼び出す正しいメソッドを VMT で検索し、そのメソッドを呼び出します。CDBMM

各クラスは独自の VMT を定義し、変数は独自の型に関連する VMT を使用します。したがって、型の変数は typeAに VMT を使用しA、型B変数は type に VMT を使用するなど、その変数に格納されているインスタンスの実際の(具体的な) クラスにB関係なく。オーバーライド解決は、インスタンスの VMT を処理して、実行する正しいメソッドを見つけます。

new演算子は、同じ名前を持つメソッドを宣言しますが、置換するメソッドの解決チェーンの一部ではありません。新しいメソッドは、独自の VMT エントリのセットを取得する仮想の場合もあれば、標準の非仮想メソッドの場合もあります。

仮想メソッドとオーバーライドを正しく管理するために、コンパイラは処理する情報を持っている必要があります。コンパイル時に変数が何を保持するかを知ることができないため、変数の型だけを使用できます。したがって、 type の変数でメソッドを呼び出すと、 typeに対して実行Aする必要があるのと同じように呼び出しが解決されAます。これは、型 A のオブジェクトでランタイム オーバーロードの解決を行うコードを生成することによって行われます。任意の型の変数についても同様です。 . 生成されたコードは宣言された型で機能し、実行時にオーバーライドを解決します。

したがって、 type の変数を宣言してCから method を呼び出すと、 で定義されているM名前のメソッドが検索されます。修飾子を使用したため、 で定義された仮想メソッドまたは でのそのオーバーロードへのバックトラッキングが発生することはありません。仮想であるため、VMT を使用して、新しい仮想メソッドの適切なオーバーライドを見つけます。MCnewABC.M

したがって、一般に、仮想メソッドが呼び出されたときに実際にどのメソッドが呼び出されるかは、インスタンスの具象型に依存します。newキーワードにより、変数の型も重要になります。

上記のいくつかは、技術的に正確というよりも記述的に正確です。いつものように、実際の実装は異なる場合があります:)

于 2013-05-29T23:52:45.680 に答える