回答:
オーバーライド修飾子は仮想メソッドで使用でき、抽象メソッドで使用する必要があります。これは、コンパイラーが最後に定義されたメソッドの実装を使用することを示します。メソッドが基本クラスへの参照で呼び出された場合でも、それをオーバーライドする実装を使用します。
public class Base
{
public virtual void DoIt()
{
}
}
public class Derived : Base
{
public override void DoIt()
{
}
}
Base b = new Derived();
b.DoIt(); // Calls Derived.DoIt
Derived.DoIt
オーバーライドする場合に呼び出されますBase.DoIt
。
新しい修飾子は、親クラスの実装の代わりに子クラスの実装を使用するようにコンパイラーに指示します。クラスを参照していないが親クラスを参照するコードは、親クラスの実装を使用します。
public class Base
{
public virtual void DoIt()
{
}
}
public class Derived : Base
{
public new void DoIt()
{
}
}
Base b = new Derived();
Derived d = new Derived();
b.DoIt(); // Calls Base.DoIt
d.DoIt(); // Calls Derived.DoIt
最初に電話しBase.DoIt
、次に電話しますDerived.DoIt
。これらは、派生メソッドが基本メソッドをオーバーライドするのではなく、事実上同じ名前を持つ2つの完全に別個のメソッドです。
出典:Microsoftブログ
This indicates for the compiler to use the last defined implementation of a method
。メソッドの最後に定義された実装をどのように見つけることができますか?
override
、基本クラスでメソッドがとして定義されている場合にのみメソッドを使用できることに注意してくださいvirtual
。単語はvirtual
、基本クラスIは、このメソッドを呼び出したとき、私は本当に私が実際に実行時に呼んでいるものをメソッドの実装事前に知っていないので、ちょっと、それは事実上、派生実装に置き換えられている可能性」と言っている。だから、のvirtual
が意味あります。メソッドのプレースホルダは、これはとしてマークされない方法を意味virtual
オーバーライドすることはできませんがしかし、あなたがすることができます。置き換える修飾子を派生クラスで任意の非仮想メソッドをnew
派生レベルでのみアクセスでき、。
virtual:メソッドが継承者によってオーバーライドされる可能性があることを示します
override:基本クラスの仮想メソッドの機能をオーバーライドして、さまざまな機能を提供します。
new:元のメソッド(仮想である必要はありません)を非表示にし、さまざまな機能を提供します。これは絶対に必要な場合にのみ使用してください。
メソッドを非表示にしても、基本クラスにアップキャストすることで元のメソッドにアクセスできます。これは一部のシナリオでは便利ですが、危険です。
override
、および/またはnew
なしでvirtual
、親法上の?
最初のケースでは、親クラスの定義を隠しています。これは、オブジェクトを子クラスとして処理しているときにのみ呼び出されることを意味します。クラスを親の型にキャストすると、親のメソッドが呼び出されます。2番目のインスタンスでは、メソッドがオーバーライドされ、オブジェクトが子クラスまたは親クラスとしてキャストされているかどうかに関係なく呼び出されます。
ケース1で、型が基本クラスとして宣言されているときに継承クラスのDoIt()メソッドを呼び出して使用した場合、基本クラスのアクションも表示されます。
/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
public void DoIt() { Console.WriteLine("Base1"); }
}
public class Class1 : Base1
{
public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
var c1 = new Class1();
c1.DoIt();
((Base1)c1).DoIt();
var c2 = new Class2();
c2.DoIt();
((Base2)c2).DoIt();
Console.Read();
}
2つのケースの違いは、ケース1では、ベースDoIt
メソッドがオーバーライドされず、単に隠されるだけです。これは、変数のタイプに応じて、呼び出されるメソッドに依存することを意味しています。例えば:
BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method
SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method
これは本当に混乱する可能性があり、予期しない動作を引き起こす可能性があるため、可能であれば回避する必要があります。したがって、推奨される方法はケース2です。
new
は、REFERENCEタイプ(の左側)を尊重して=
、参照タイプのメソッドを実行することを意味します。再定義されたメソッドにnew
キーワードがない場合は、そのように動作します。さらに、それは非多相継承としても知られています。つまり、「基本クラスの同じ名前のメソッドとはまったく関係のない、まったく新しいメソッドを派生クラスで作成しています。」-言ったウィテカーoverride
virtual
は、基本クラスでキーワードとともに使用する必要があるため、OBJECTタイプ(の右側)を尊重し、=
参照タイプに関係なくオーバーライドされたメソッドを実行することを意味します。さらに、それは多相継承としても知られています。
両方のキーワードが互いに反対であることを覚えておくための私の方法。
override
:virtual
メソッドをオーバーライドするには、キーワードを定義する必要があります。override
キーワードを使用するメソッド。参照タイプ(基本クラスまたは派生クラスの参照)に関係なく、基本クラスでインスタンス化された場合、基本クラスのメソッドが実行されます。それ以外の場合は、派生クラスのメソッドが実行されます。
new
:キーワードがメソッドによって使用される場合、キーワードとは異なりoverride
、参照タイプは重要です。派生クラスでインスタンス化され、参照型が基本クラスの場合、基本クラスのメソッドが実行されます。派生クラスでインスタンス化され、参照型が派生クラスである場合、派生クラスのメソッドが実行されます。つまり、override
キーワードの対比です。ちなみに、メソッドに新しいキーワードを追加するのを忘れたり省略したりすると、new
キーワードが使用されるため、コンパイラはデフォルトで動作します。
class A
{
public string Foo()
{
return "A";
}
public virtual string Test()
{
return "base test";
}
}
class B: A
{
public new string Foo()
{
return "B";
}
}
class C: B
{
public string Foo()
{
return "C";
}
public override string Test() {
return "derived test";
}
}
メインで呼び出す:
A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());
Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());
出力:
A
B
B
base test
derived test
新しいコード例、
class X
{
protected internal /*virtual*/ void Method()
{
WriteLine("X");
}
}
class Y : X
{
protected internal /*override*/ void Method()
{
base.Method();
WriteLine("Y");
}
}
class Z : Y
{
protected internal /*override*/ void Method()
{
base.Method();
WriteLine("Z");
}
}
class Programxyz
{
private static void Main(string[] args)
{
X v = new Z();
//Y v = new Z();
//Z v = new Z();
v.Method();
}
私は同じ質問をしましたが、それは本当に混乱します。基本クラスのオブジェクトと派生クラスの値でのみ機能するオーバーライドと新しいキーワードを検討する必要があります。この場合、あなただけがオーバーライドして、新しいの効果を見ることができます:あなたが持っているので、場合class A
とB
、B
から継承しA
、その後、あなたは、このようなオブジェクトをインスタンス化します。
A a = new B();
次に、メソッドを呼び出すときにその状態を考慮します。 オーバーライド:メソッドの機能を拡張し、派生クラスのメソッドを使用するのに対し、newはコンパイラに派生クラスのメソッドを非表示にし、代わりに基本クラスのメソッドを使用するように指示します。ここにその主題への非常に良い光景があります:
以下の記事はvb.netにありますが、新しいvsオーバーライドに関する説明は非常に理解しやすいと思います。
https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides
記事のある時点で、次の文があります。
一般に、Shadowsは型に関連付けられた関数が呼び出されることを想定し、Overridesはオブジェクト実装が実行されることを想定しています。
この質問に対する受け入れられた回答は完璧ですが、この記事は、これら2つのキーワードの違いについてより良い意味を追加するための良い例を提供していると思います。
これらすべての中で、新しいものが最も混乱します。実験を通じて、新しいキーワードは、型を明示的に定義することによって、継承クラスの実装を基本クラスの実装でオーバーライドするオプションを開発者に与えるようなものです。それは逆に考えるようなものです。
以下の例では、タイプがBaseClassテストとして明示的に定義されるまで、結果は「派生結果」を返します。その後、「基本結果」のみが返されます。
class Program
{
static void Main(string[] args)
{
var test = new DerivedClass();
var result = test.DoSomething();
}
}
class BaseClass
{
public virtual string DoSomething()
{
return "Base result";
}
}
class DerivedClass : BaseClass
{
public new string DoSomething()
{
return "Derived result";
}
}
これらのテストでは、機能の違いは示されません。
BaseClass bc = new BaseClass();
bc.DoIt();
DerivedClass dc = new DerivedClass();
dc.ShowIt();
この例では、呼び出されるDoitは、呼び出されると予想されるものです。
違いを確認するには、次のようにする必要があります。
BaseClass obj = new DerivedClass();
obj.DoIt();
ケース1(定義したとおり)でDoIt()
in BaseClass
が呼び出され、ケース2(定義したとおり)でDoIt()
in DerivedClass
が呼び出されるテストを実行するかどうかがわかります。
最初のケースでは、新しいキーワードが基本クラスのDoIt()メソッドを隠すため、派生クラスのDoIt()メソッドを呼び出します。
2番目のケースでは、オーバーライドされたDoIt()を呼び出します
public class A
{
public virtual void DoIt()
{
Console.WriteLine("A::DoIt()");
}
}
public class B : A
{
new public void DoIt()
{
Console.WriteLine("B::DoIt()");
}
}
public class C : A
{
public override void DoIt()
{
Console.WriteLine("C::DoIt()");
}
}
これらのクラスのインスタンスを作成しましょう
A instanceA = new A();
B instanceB = new B();
C instanceC = new C();
instanceA.DoIt(); //A::DoIt()
instanceB.DoIt(); //B::DoIt()
instanceC.DoIt(); //B::DoIt()
上ですべてが期待されています。instanceBとinstanceCをinstanceAに設定し、DoIt()メソッドを呼び出して結果を確認します。
instanceA = instanceB;
instanceA.DoIt(); //A::DoIt() calls DoIt method in class A
instanceA = instanceC;
instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C