17

メモリと参照の観点から、オーバーライドと非表示の作業を誰かに教えてもらえますか。

class A
{
    public virtual void Test1() { //Impl 1}
    public virtual void Test2() { //Impl 2}
}
class B  : A
{
    public override void Test1() { //Impl 3}
    public new void Test2() { Impl 4}
}

static Main()
{
    A aa=new B() //This will give memory to B
    aa.Test1(); //What happens in terms of memory when this executes
    aa.Test2(); //-----------------------SAME------------------------
}

ここでメモリはクラス B にありますが、2 番目のステートメントaa.Test2 ではクラス A のメソッドが呼び出されます。それはなぜです?B にメモリがある場合、B のメソッドを呼び出す必要があります (私の観点では)。

この基本を非常に深く完全に説明しているリンク/演習は、大きな助けになります。

4

9 に答える 9

31

Eric Lippert による別の質問に対するこの回答をご覧ください。

(私の理解の限界まで)言い換えると、これらのメソッドは「スロット」に入ります。には、 用とA用の 2 つのスロットがあります。Test1Test2

A.Test1は とマークされvirtualB.Test1とマークされているため、overrideB実装はTest1独自のスロットを作成せず、 の実装を上書きしますABのインスタンスをとして扱うか にBキャストするかに関係なくA、同じ実装がそのスロットにあるため、常に の結果が得られますB.Test1

対照的に、B.Test2は とマークされnewているため、独自の新しいスロットを作成します。(マークされていなくてnewも、別の名前が付けられた場合と同様です。)Aの実装はTest2、独自のスロットにまだ「そこに」あります。上書きされるのではなく、隠されています。のインスタンスをBとして扱うと、 ;Bが得られます。B.Test2にキャストすると、新しいスロットが表示Aされず、呼び出されます。A.Test2

于 2012-06-15T07:57:19.633 に答える
6

@Rawling の回答に追加するには、次のような例を使用して実用的な例を示すことができます。

class Base
{
    // base property
    public virtual string Name
    {
        get { return "Base"; }
    }
}

class Overriden : Base
{
    // overriden property
    public override string Name
    {
        get { return "Overriden"; }
    }
}

class New : Base
{
    // new property, hides the base property
    public new string Name
    {
        get { return "New"; }
    }
}

1.オーバーライド

オーバーライドされたプロパティの場合、基本クラスの仮想メソッドのスロットは別の実装に置き換えられます。コンパイラはメソッドをvirtualと見なし、実行時にオブジェクトの仮想テーブルを使用してその実装を解決する必要があります。

{
    Base b = new Base();
    Console.WriteLine(b.Name); // prints "Base"

    b = new Overriden();
    // Base.Name is virtual, so the vtable determines its implementation
    Console.WriteLine(b.Name); // prints "Overriden"

    Overriden o = new Overriden();
    // Overriden.Name is virtual, so the vtable determines its implementation
    Console.WriteLine(o.Name); // prints "Overriden"
}

2.隠れる

キーワードを使用してメソッドまたはプロパティを非表示newにすると、コンパイラは派生クラスに対してのみ新しい非仮想メソッドを作成します。基本クラスのメソッドは変更されません。

変数の型がBase(つまり、仮想メソッドのみを含む) 場合、その実装は vtable を通じて解決されます。変数の型が の場合New、非仮想メソッドまたはプロパティが呼び出されます。

{
    Base b = new Base();
    Console.WriteLine(b.Name); // prints "Base"

    b = new New();
    // type of `b` variable is `Base`, and `Base.Name` is virtual,
    // so compiler resolves its implementation through the virtual table
    Console.WriteLine(b.Name); // prints "Base"

    New n = new New();
    // type of `n` variable is `New`, and `New.Name` is not virtual,
    // so compiler sees `n.Name` as a completely different property
    Console.WriteLine(n.Name); // prints "New"
}

3. まとめ

コードの一部が基本型を受け入れる場合、実行時に常に仮想テーブルが使用されます。ほとんどの OOP シナリオでは、これは、メソッドを としてマークするnewことは、まったく異なる名前を付けることに非常に似ていることを意味します。

4.インスタンス化後のオブジェクトサイズ

これらの型をインスタンス化しても、仮想テーブルのコピーは作成されないことに注意してください。各 .NET オブジェクトには、数バイトのヘッダーと、そのタイプのテーブルの仮想テーブルへのポインター ( class) があります。

プロパティ (仮想ではないもの)に関してnewは、基本的に thiscall セマンティクスを使用して静的メソッドとしてコンパイルされます。つまり、メモリ内のインスタンスのサイズにも何も追加されません。

于 2012-06-15T08:42:19.610 に答える
3

Already answered at here

Overriding is the definition of multiple possible implementations of the same method signature, such that the implementation is determined by the runtime type of the zeroth argument (generally identified by the name this in C#).

非表示とは、オーバーライドせずに基本型の 1 つと同じシグネチャを持つ派生型のメソッドの定義です。

オーバーライドと非表示の実際の違いは次のとおりです。

非表示は、他のすべてのメンバー (静的メソッド、インスタンス メンバー、静的メンバー) 用です。早期バインディングに基づいています。より明確に、呼び出されるか使用されるメソッドまたはメンバーは、コンパイル時に決定されます。

•メソッドがオーバーライドされている場合、呼び出す実装は、引数 this の実行時の型に基づいています。•メソッドが単純に隠されている場合、呼び出す実装は引数 this のコンパイル時の型に基づいています。

以下にいくつかのサンプルを示します。および例#2

于 2012-06-15T07:39:41.170 に答える
1

クラス A の Test1() メソッドとクラス B の test1() メソッドは、MethdOverridingに従って実行されます。

クラス A の Test2() メソッドとクラス B の test2() メソッドは、 Method Hidingに従って実行されます。

メソッドのオーバーライドでは子クラスのメンバーが実行され、メソッドの非表示では親クラスのメンバーが実行されます。

于 2014-07-11T09:48:05.657 に答える
0

メソッドまたはプロパティを非表示にすることで、そのタイプのオブジェクトがある場合に、そのようなメソッドがポリモーフィックになるのを止めたいと言っているだけです。さらに、非表示のメソッドは非多態的な方法で呼び出されるため、これらのメソッドタイプを呼び出すには、単純に非仮想メソッドであるため、コンパイル時に知る必要があります。

于 2012-06-15T07:47:13.367 に答える
0
 public class BaseClass
    {
      public void PrintMethod()
      {
       Console.WriteLine("Calling base class method");
      }
     }
     public class ChildClass
     {
      public new void PrintMethod()
      {
       Console.WriteLine("Calling the child or derived class method");
       }
      }
      class Program
      {
       static void Main()
       {
        BaseClass bc = new ChildClass();
        bc.PrintMethod();
        }
       }

メソッドの非表示は、基本クラスが子クラス オブジェクトを指す変数を参照する場合です。基本クラスの隠しメソッドを呼び出します。

ここで、基本クラスで仮想メソッドを宣言すると。派生クラスまたは子クラスでそのメソッドをオーバーライドします。次に、基本クラスの参照変数が派生クラスのメソッドを呼び出します。これはメソッドのオーバーライドと呼ばれます。

于 2015-05-07T08:05:37.700 に答える
0

提供されたコードから控除する必要がありますB:A

オーバーライドできない基本クラスの (たとえば) メソッドの独自の実装を作成する場合に備えて、メソッドを非表示にすることができますvirtual

私の経験では、 主に目的のために非表示debugを使用していました。

たとえば、誰が 3rd prt のプロパティを設定したのかわからない場合component、誰のコードを利用できませんか。だから私がすることは次のとおりです。

  • コンポーネントから子クラスを作成する
  • newキーワードで興味のあるプロパティを隠す
  • ブレークポイントを入れるset
  • いつヒットするかを待ちます。

時々、非常に便利で、特に新しいことを学ぶ最初の段階で、情報をすばやく取得するのに役立ちますcomponents..frameworkslibrariesでも.

于 2012-06-15T07:33:32.030 に答える
0

簡単に言えば、メソッドまたはプロパティをオーバーライドする場合、オーバーライド メソッドは基本メソッドと同じシグネチャを持つ必要があります。これを非表示にする必要がない場合、新しいオブジェクトは以下に示すように任意の形式を取ることができます

// base
    public int GrossAmount { get; set; }

    // hiding base
    public new string GrossAmount
    {
        get;
        set;             
    }
于 2012-06-15T07:36:38.297 に答える