誰もがメモリと参照の観点からオーバーライドと非表示の動作を伝えることができますか?.
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のメソッドを呼び出す必要があります(私の観点では)。
この基本を非常に深く完全に説明するリンク/演習は、大きな助けになります。
別の質問に対するこの回答 を見てください。EricLippertによる。
言い換えると(私の理解の限界まで)、これらのメソッドは「スロット」に入ります。 A
には2つのスロットがあります。1つはTest1
用、もう1つはTest2
用です。
A.Test1
はvirtual
としてマークされ、B.Test1
はoverride
としてマークされるため、B
のTest1
の実装は独自のスロットを作成せず、A
の実装を上書きします。 B
のインスタンスをB
として扱う場合でも、A
にキャストする場合でも、同じ実装がそのスロットにあるため、常にB.Test1
の結果が得られます。
対照的に、B.Test2
はnew
とマークされているため、独自のnewスロットを作成します。 (new
とマークされていないが、別の名前が付けられている場合と同じように。)A
のTest2
の実装は、それ自体のスロットにまだ「あります」。上書きされるのではなく、非表示になっています。 B
のインスタンスをB
として扱うと、B.Test2
が得られます。それをA
にキャストすると、新しいスロットを見ることができず、A.Test2
が呼び出されます。
@ 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。オーバーライド
overridenプロパティの場合、基本クラスの仮想メソッドのスロットは置換されます別の実装による。コンパイラはメソッドを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
キーワードを使用してhiddenの場合、コンパイラは新しいを作成します派生クラスのみの非仮想メソッド。基本クラスのメソッドは変更されません。
変数のタイプが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。インスタンス化後のオブジェクトサイズ
instantiatingこれらのタイプのいずれも、仮想テーブルのコピーを作成しないことに注意してください。各.NETオブジェクトには、数バイトのヘッダーと、そのタイプのテーブルの仮想テーブル(class
)へのポインターがあります。
new
プロパティ(仮想ではないプロパティ)に関しては、基本的にthiscallセマンティクスを使用して静的メソッドとしてコンパイルされます。つまり、メモリ内のインスタンスのサイズに何も追加されません。
すでに ここ で回答済み
オーバーライドは、同じメソッドシグネチャの複数の可能な実装の定義であり、実装は0番目の引数の実行時型(通常、C#ではthisという名前で識別されます)によって決定されます。
Hidingは、派生型のメソッドの定義であり、その基本型の1つと同じシグネチャをオーバーライドせずに使用します。
オーバーライドと非表示の実際的な違いは次のとおりです。
非表示は他のすべてのメンバー(静的メソッド、インスタンスメンバー、静的メンバー)用です。これは、初期のバインディングに基づいています。より明確に言えば、呼び出されるか使用されるメソッドまたはメンバーは、コンパイル時に決定されます。
•メソッドがオーバーライドされた場合、呼び出す実装は、引数thisの実行時タイプに基づいています。 •メソッドが単に非表示になっている場合、呼び出す実装は、引数thisのコンパイル時の型に基づいています。
クラスAのTest1()メソッドとクラスBのtest1()メソッドは、MethdOverridingに従って実行されます。
クラスAのTest2()メソッドとクラスBのtest2()メソッドは、メソッド非表示に従って実行されます。
メソッドではオーバーライド子クラスのメンバーが実行され、メソッドの非表示では親クラスのメンバーが実行されます。
提供されたコードから差し引くと、B:A
。
基本クラスの(たとえば)メソッドの独自の実装を作成する場合に備えて、メソッドを非表示にすることができます。これはできないオーバーライドされます。たとえば、virtual
ではありません。 。
私の経験では、私はhidingを主にdebug
の目的で使用しました。
たとえば、3番目のprt component
のプロパティを誰が設定するのかわからない場合、誰のコードを使用できません。だから私がすることは:
new
キーワードで関心のあるプロパティを非表示にしますset
に置きます時々、非常に便利で、特に新しいcomponents
、frameworks
、libraries
..を学習している最初の段階で、情報をすばやく取得するのに役立ちます。
簡単に言えば、メソッドまたはプロパティをオーバーライドする場合、オーバーライドメソッドは基本メソッドと同じシグネチャを持っている必要があります。これを非表示にする必要がない場合、新しいオブジェクトは次のように任意の形式をとることができます
// base
public int GrossAmount { get; set; }
// hiding base
public new string GrossAmount
{
get;
set;
}
class Base {
int a;
public void Addition() {
Console.WriteLine("Addition Base");
}
public virtual void Multiply()
{
Console.WriteLine("Multiply Base");
}
public void Divide() {
Console.WriteLine("Divide Base");
}
}
class Child : Base
{
new public void Addition()
{
Console.WriteLine("Addition Child");
}
public override void Multiply()
{
Console.WriteLine("Multiply Child");
}
new public void Divide()
{
Console.WriteLine("Divide Child");
}
}
class Program
{
static void Main(string[] args)
{
Child c = new Child();
c.Addition();
c.Multiply();
c.Divide();
Base b = new Child();
b.Addition();
b.Multiply();
b.Divide();
b = new Base();
b.Addition();
b.Multiply();
b.Divide();
}
}
出力:-
追加の子
子を掛ける
子を分割する
追加ベース
子を掛ける
ベースを分割する
追加ベース
基数を掛ける
ベースを分割する
コンパイラは、オーバーライド時にクラスのオブジェクトをチェックしますが、非表示の場合、コンパイラはクラスの参照のみをチェックします。
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();
}
}
メソッドの非表示は、基本クラスの参照変数が子クラスオブジェクトを指している場合です。基本クラスの隠しメソッドを呼び出します。
一方、基本クラスで仮想メソッドを宣言する場合。派生クラスまたは子クラスでそのメソッドをオーバーライドします。次に、基本クラス参照変数は派生クラスメソッドを呼び出します。これはメソッドのオーバーライドと呼ばれます。
メソッドまたはプロパティを非表示にすることで、そのタイプのオブジェクトがある場合に、そのようなメソッドが多形になるのを止めたいと言っているだけです。さらに、非表示のメソッドは非多態的な方法で呼び出されるため、これらのメソッドタイプを呼び出すには、単純に非仮想メソッドであるため、コンパイル時に知る必要があります。