web-dev-qa-db-ja.com

仮想メソッドとは何ですか?

メソッドを「仮想」として宣言するのはなぜですか。

仮想を使用する利点は何ですか?

69
mtnclimber10

Virtual 修飾子は、 オーバーライド 修飾子を使用して、派生クラスでmethod\property(ect)を変更できることを示すために使用されます。

例:

class A
{
    public virtual void Foo()
       //DoStuff For A
}

class B : A
{
    public override void Foo()
    //DoStuff For B

    //now call the base to do the stuff for A and B 
    //if required
    base.Foo()
}
50
cgreeno

仮想の継承クラスは、基本クラスは、次に使用する方法を置き換えることができます。

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.

ウィジェットがThingyレベルで定義されたAction()メソッドを呼び出したのに、内部的にはThingyがWidgetのStepA()メソッドを呼び出したことに注意してください。

基本的な答えは、クラスの継承者に柔軟性を与えることです。もちろん、あなたも自分のクラスを設計するために持っているか、それが弱い大混乱をできました。

41
Ludington

仮想メソッドは、実際のメソッド呼び出しが基礎となるオブジェクトのランタイムタイプに依存するメソッドのタイプです。

非仮想メソッドは、呼び出される実際のメソッドがメソッド呼び出しの時点でオブジェクトの参照タイプに依存するメソッドのタイプです。

21
JaredPar

MSDNの仮想メソッド

Virtualキーワードは、メソッドまたはプロパティの宣言を変更するために使用されます。その場合、メソッドまたはプロパティは仮想メンバーと呼ばれます。仮想メンバーの実装は、派生クラスのオーバーライドメンバーによって変更できます。

仮想メソッドが呼び出されると、オブジェクトの実行時の型がオーバーライドするメンバーについてチェックされます。最も派生したクラスのオーバーライドするメンバーが呼び出されます。派生したクラスがメンバーをオーバーライドしていない場合は、元のメンバーである可能性があります。 (実行時型と最も派生した実装の詳細については、10.5.3仮想メソッドを参照してください。)

デフォルトでは、メソッドは非仮想です。非仮想メソッドをオーバーライドすることはできません。

Virtual修飾子を次の修飾子と一緒に使用することはできません。

staticabstractoverride

仮想プロパティは、宣言と呼び出し構文の違いを除いて、抽象メソッドのように動作します。

  • 静的プロパティで仮想修飾子を使用するとエラーになります。
  • 仮想継承プロパティは、オーバーライド修飾子を使用するプロパティ宣言を含めることにより、派生クラスでオーバーライドできます。
13
Russ Cam

クラスから派生する予定がない場合でも、クラスをモックするためにメソッドを仮想にマークする必要がある場合があります。一部のモックフレームワークでは、仮想メソッドのみをモックできます。インターフェイスを実装するメソッドは暗黙的に仮想であることに注意してください。

この制限があるRhinoMocksを使用し、この理由でデフォルトでメソッドを仮想としてマークしました。私にとって、これはおそらく、継承が関係するケースがはるかに少ないため、仮想メソッドを使用する最大の理由です。

6
tvanfosson

仮想メソッドは、派生クラスでの実装がオプションであることを除き、基本クラスの抽象メソッドに似ています。また、仮想メソッドにロジックを配置し、派生クラスでこれらをオーバーライドすることもできます。

5
cyclo

継承クラスでそれをオーバーライドできるようにするため。

キーワードの MSDNエントリ を確認してください。それはより深くそれを説明します。

3
PHeiberg

短い質問、短い答え!メソッドが属するクラスを継承すると思われる場合は、メソッドを「仮想」として修飾します。

より長い答え:「仮想により、派生クラスでメソッドの別の意味を与えるためにオーバーライドできます。

3
Stephane Halimi

仮想関数は、実際には存在しない関数です。派生クラスは、仮想関数をオーバーライドすることにより変更できます。仮想関数は、実行時ポリモーフィズムを実現する方法の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();
      }
    }
1
Lineesh K Mohan

ここでは例で明確に説明されています C#Virtual Method

1
Hitsa

言うまでもなく、コードが Open Closed Principle を順守しようとしている場合、仮想メソッドが役立ちます。

Open Closed Principleの詳細を読む here 、Uncle BobのオリジナルOCPホワイトペーパー。

また、plsは、Javaとは異なり、C#でデフォルトでメソッドがnot仮想であることに注意してください。

1
abhilash

ランタイムはコンパイル時に行われます。
メソッドを仮想として宣言する場合、派生クラスでメソッドを宣言するには、overrideまたはnew修飾子を追加する必要があります。
TrySpeakのとき、それがわかります。子と父を渡すと、両方とも父といえば呼び出しますが、TryScreamはそれぞれのメソッドを呼び出します。
これを理解するために、Childのインスタンスには、ChildクラスまたはFatherクラスの2つのScreamメソッドがあることを知っておく必要があります。 ChildクラスまたはFatherクラスからScreamを呼び出すことができます。 Virtaul修飾子はメソッドをマークするため、派生クラスによってオーバーライドできます。つまり、Screamでも、Fatherクラスから呼び出されるため、オーバーライドされます。新しい修飾子を使用する場合は異なります。 。

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();
    }
}
1
soulomoon

仮想メソッドと非仮想メソッドの違い。

2つのクラスがあります。 1つはVehicleクラスで、もう1つはCartクラスです。 「Vehicle」クラスは、2つのメソッドを持つ基本クラスです。 1つは仮想メソッド「Speed()」で、もう1つは非仮想メソッド「Average()」です。そのため、基本クラスの仮想メソッド「Speed()」はサブクラスでオーバーライドされます。サブクラス「Cart」のインスタンスを作成するエントリポイントを持つもう1つのクラス「Program」(実行クラス)があり、そのインスタンスは基本クラス「Vehicle」タイプに割り当てられます。両方のクラスのインスタンスによって仮想メソッドと非仮想メソッドを呼び出すと、実行タイプに従ってインスタンス仮想メソッドの実装が呼び出されます。言い換えると、両方のクラスのインスタンスがサブクラスオーバーライドメソッドを呼び出し、呼び出された非仮想メソッドはクラスのインスタンスに基づいて決定されます。

using System;

namespace VirtualExample
{   
    class Vehicle
    {   
       public double distance=0.0;
       public double hour =0.0;
       public double fuel =0.0; 

       public Vehicle(double distance, double hour, double fuel)
       {
           this.distance = distance;
           this.hour = hour;
           this.fuel = fuel;
       }

       public void Average()
       {
           double average = 0.0;
           average = distance / fuel;
           Console.WriteLine("Vehicle Average is {0:0.00}", average);
       }

       public virtual void Speed()
       {
           double speed = 0.0;
           speed = distance / hour;
           Console.WriteLine("Vehicle Speed is {0:0.00}", speed);
       }
    } 

    class Car : Vehicle
    {
        public Car(double distance, double hour, double fuel)
            : base(distance, hour, fuel)
        {
        }
      public void Average()
        {
            double average = 0.0;
            average = distance / fuel;
            Console.WriteLine("Car Average is {0:0.00}", average);
        }

        public override void Speed()
        {
            double speed = 0.0;           
            speed = distance / hour;
            Console.WriteLine("Car Speed is {0:0.00}", speed);
        }
    } 

    class Program
   {
        static void Main(string[] args)
        {
             double distance,hour,fuel=0.0;
             Console.WriteLine("Enter the Distance");
             distance = Double.Parse(Console.ReadLine());
             Console.WriteLine("Enter the Hours");
             hour = Double.Parse(Console.ReadLine());
             Console.WriteLine("Enter the Fuel");
             fuel = Double.Parse(Console.ReadLine());
             Car objCar = new Car(distance,hour,fuel);
             Vehicle objVeh = objCar;
             objCar.Average();
             objVeh.Average();
             objCar.Speed();
             objVeh.Speed();
            Console.Read();
        }       
    }
}

enter image description here

助けて欲しい!

1
alvarodoune

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();
 }
 }
}

派生クラスのメソッドは同時に仮想であるため、仮想キーワードと新しいキーワードを使用して、メソッドの非表示とメソッドのオーバーライドを混在させることもできます。これは、次に示すようにクラス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();
 }
 }
}

ゴールデンワード:仮想キーワードは、基本クラスで宣言されたメソッド、プロパティ、インデクサー、またはイベントを変更し、派生クラスでオーバーライドできるようにするために使用されます。

Overrideキーワードは、基本クラスのvirtual/abstractメソッド、プロパティ、インデクサー、またはイベントを派生クラスに拡張または変更するために使用されます。

新しいキーワードは、基本クラスのメソッド、プロパティ、インデクサー、またはイベントを派生クラスに非表示にするために使用されます。

楽しい :-)

0
Rana Bhopale

このリンクは、非常に簡単な例でより良い理解を提供します https://stackoverflow.com/a/2392656/3373865

0
Anand Kumar Jha