メソッドを「仮想」として宣言するのはなぜですか。
仮想を使用する利点は何ですか?
メソッドを「仮想」として宣言するのはなぜですか。
仮想を使用する利点は何ですか?
回答:
Virtualを使用すると、継承クラスで、基本クラスが使用するメソッドを置き換えることができます。
public class Thingy
{
public virtual void StepA()
{
Console.Out.WriteLine("Zing");
}
public void Action()
{
StepA();
Console.Out.WriteLine("A Thingy in Action.");
}
}
public class Widget : Thingy
{
public override void StepA()
{
Console.Out.WriteLine("Wiggy");
}
}
class Program
{
static void Main(string[] args)
{
Thingy thingy = new Thingy();
Widget widget = new Widget();
thingy.Action();
widget.Action();
Console.Out.WriteLine("Press any key to quit.");
Console.ReadKey();
}
}
プログラムを実行すると、出力は次のようになります。
Zing
A Thingy in Action.
Wiggy
A Thingy in Action.
WidgetがThingyレベルで定義されたAction()メソッドを呼び出したにもかかわらず、内部的にThingyがWidgetのStepA()メソッドを呼び出したことに注意してください。
基本的な答えは、クラスの継承者に柔軟性を与えることです。もちろん、クラスをうまく設計する必要があります。そうしないと、大混乱が弱まる可能性があります。
virtualキーワードは、メソッドまたはプロパティの宣言を変更するために使用されます。この場合、メソッドまたはプロパティは仮想メンバーと呼ばれます。仮想メンバーの実装は、派生クラスのメンバーをオーバーライドすることで変更できます。
仮想メソッドが呼び出されると、オブジェクトの実行時型がオーバーライドメンバーについてチェックされます。最も派生したクラスのオーバーライドメンバーが呼び出されます。派生クラスがメンバーをオーバーライドしていない場合は、元のメンバーである可能性があります。(実行時型とほとんどの派生実装の詳細については、10.5.3仮想メソッドを参照してください。)
デフォルトでは、メソッドは非仮想です。非仮想メソッドをオーバーライドすることはできません。
仮想修飾子を次の修飾子と一緒に使用することはできません。
静的 抽象 オーバーライド
仮想プロパティは、宣言と呼び出し構文の違いを除いて、抽象メソッドのように動作します。
- 静的プロパティで仮想修飾子を使用するとエラーになります。
- 仮想継承プロパティは、オーバーライド修飾子を使用するプロパティ宣言を含めることにより、派生クラスでオーバーライドできます。
クラスから派生する予定がない場合でも、クラスをモックするためにメソッドを仮想としてマークする必要がある場合があります。一部のモックフレームワークでは、仮想メソッドのモックのみが許可されます。インターフェイスを実装するメソッドは暗黙的に仮想であることに注意してください。
私はこの制限があるRhinoMocksを使用しており、この理由だけでデフォルトでメソッドを仮想としてマークしています。私にとって、これはおそらく、継承が機能するケースがはるかに少ないため、仮想メソッドを使用する最大の理由です。
言うまでもなく、仮想メソッドは、コードがOpen ClosedPrincipleに準拠しようとしているときに役立ちます。
オープンクローズド原則の詳細については、こちらをご覧ください、ボブおじさんのオリジナルのOCPホワイトペーパーを。
また、Javaとは異なり、C#ではメソッドがデフォルトで仮想ではないことに注意してください。
仮想関数は、実際には存在しない関数です。派生クラスは、仮想関数をオーバーライドすることで変更できます。仮想関数は、実行時のポリモーフィズムを実現する方法の1つです。
public class sample {
public virtual void fun(){
Console.WriteLine("base sample class \n");
}
}
public class A : sample{
public override void fun(){
Console.WriteLine("Class A \n");
}
}
public class B : sample{
public override void fun(){
Console.WriteLine("Class B \n");
}
}
class run{
public static void main(String[] args){
sample obj = new sample();
sample obj1 = new A();
sample obj2 = new B();
obj.fun();
obj1.fun();
obj2.fun();
}
}
public
後の アクセス修飾子はclass A
、class B
コンパイル時エラーを引き起こします。派生クラスからの基本クラスのメンバーのアクセス可能性は、基本クラスから個別に指定されます(デフォルトではメンバーはですprivate
)。
ランタイムはコンパイル時に発生します。
メソッドを仮想として宣言する場合、派生クラスで宣言するには、override
またはnew
修飾子を追加する必要があります。
いつそれを見ることができますTrySpeak
。子と父親を渡すと、どちらもSpeak of FatherをTryScream
呼び出しますが、はそれぞれのメソッドを呼び出します。
これを理解するために、知っておくべきことがいくつかあります。ChildのインスタンスではScream
、ChildクラスまたはFatherクラスの2つのメソッドがあります。Scream
fromChildクラスまたはFatherクラスのいずれかを呼び出すことができます。のでVirtaul
それも手段派生クラスでオーバーライドすることができますので、修飾子は、メソッドをマークScream
父クラスから呼び出され、それはあなたが新しい修飾子を使用している場合、それはdefferentになり、上書きされます。
import system;
class Father
{
Speak()
{
Console.Writeline("Father is speaking")
}
virtual Scream()
{
Console.Writeline("Father is screaming")
}
}
class Child: father
{
Speak()
{
Console.Writeline("Child is speaking")
}
override Scream()
{
Console.Writeline("Child is screaming")
}
}
class APP
{
public static void Main()
{
// We new two instances here
Father father = new Father();
Child child = new Child();
// Here we call their scream or speak through TryScream or TrySpeak
TrySpeak(father);
TrySpeak(child);
//>>>"Father is speaking"
//>>>"Father is speaking"
TryScream(father);
TryScream(child);
//>>>"Father is screaming"
//>>>"Child is screaming"
}
// when your method take an Parameter who type is Father
// You can either pass in a Father instance or
// A instance of a derived Class from Father
// which could be Child
public static void TrySpeak(Father person)
{
person.Scream();
}
public static void TryScream(Father person)
{
person.Speak();
}
}
C#では、派生クラスの基本クラスメソッドをオーバーライドするには、以下に示すように、基本クラスメソッドを仮想として宣言し、派生クラスメソッドをオーバーライドとして宣言する必要があります。
using System;
namespace Polymorphism
{
class A
{
public virtual void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public override void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public override void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"
a = new B();
a.Test(); // output --> "B::Test()"
b = new C();
b.Test(); // output --> "C::Test()"
Console.ReadKey();
}
}
}
派生クラスのメソッドは仮想と新規を同時に使用できるため、virtualキーワードとnewキーワードを使用して、メソッドの非表示とオーバーライドを混在させることもできます。これは、以下に示すように、クラスCのクラスB、Test()メソッドをオーバーライドしているため、派生クラスメソッドを次のレベルにさらにオーバーライドする場合に必要です。
using System;
namespace Polymorphism
{
class A
{
public void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public new virtual void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public override void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"
a = new B();
a.Test(); // output --> "A::Test()"
b = new C();
b.Test(); // output --> "C::Test()"
Console.ReadKey();
}
}
}
GOLDEN WORDS:virtualキーワードは、基本クラスで宣言されたメソッド、プロパティ、インデクサー、またはイベントを変更し、派生クラスでオーバーライドできるようにするために使用されます。
overrideキーワードは、基本クラスの仮想/抽象メソッド、プロパティ、インデクサー、またはイベントを派生クラスに拡張または変更するために使用されます。
newキーワードは、基本クラスのメソッド、プロパティ、インデクサー、またはイベントを派生クラスに隠すために使用されます。
楽しい :-)
このリンクは、非常に簡単な例https://stackoverflow.com/a/2392656/3373865でより良い理解を提供します