Co to są metody wirtualne?

81

Dlaczego miałbyś zadeklarować metodę jako „wirtualną”.

Jakie są zalety korzystania z wirtualizacji?

HerbalMart
źródło

Odpowiedzi:

58

Wirtualnej modyfikator jest stosowany do oznaczenia, że sposób \ właściwość (ECT) może być modyfikowany w klasie pochodnej za pomocą sterowania ręcznego modyfikatora.

Przykład:

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()
}
cgreeno
źródło
45

Wirtualne umożliwia dziedziczącej klasie zastąpienie metody, której następnie używa klasa bazowa.

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

Po uruchomieniu programu Twoje wyniki będą wyglądać następująco:

Zing 
A Thingy in Action. 
Wiggy 
A Thingy in Action.

Zwróć uwagę, że chociaż Widget wywołał metodę Action () zdefiniowaną na poziomie Thingy, wewnętrznie Thingy nazywała metodę Widget's StepA ().

Podstawowa odpowiedź brzmi: daje spadkobiercom klasy większą elastyczność. Oczywiście musisz dobrze zaprojektować swoją klasę, inaczej może to spowodować małe spustoszenie.

Ludington
źródło
23

Metoda wirtualna to typ metody, w której rzeczywiste wywołania metody zależą od typu środowiska uruchomieniowego obiektu bazowego.

Metoda niewirtualna to typ metody, w której rzeczywista wywoływana metoda zależy od typu odwołania obiektu w momencie wywołania metody.

JaredPar
źródło
To powinna być odpowiedź - wirtualnego nie można zdefiniować poprzez warunki modyfikacji deklaracji. Czym różni się zatem od metody ukrywania?
SENya
13

Metody wirtualne w witrynie MSDN

Słowo kluczowe virtual służy do modyfikowania metody lub deklaracji właściwości, w którym to przypadku metoda lub właściwość nazywana jest wirtualnym składnikiem. Implementację wirtualnego elementu członkowskiego można zmienić przez zastępujący element członkowski w klasie pochodnej.

Gdy wywoływana jest metoda wirtualna, typ czasu wykonywania obiektu jest sprawdzany pod kątem zastępującego elementu członkowskiego. Wywoływany jest zastępujący element członkowski w klasie najbardziej pochodnej, który może być oryginalnym elementem członkowskim, jeśli żadna klasa pochodna nie przesłania elementu członkowskiego. (Aby uzyskać więcej informacji na temat typu czasu wykonywania i większości pochodnych implementacji, zobacz 10.5.3 Metody wirtualne).

Domyślnie metody nie są wirtualne. Nie można zastąpić metody niewirtualnej.

Nie możesz używać wirtualnego modyfikatora z następującymi modyfikatorami:

statyczne zastąpienie abstrakcyjne

Właściwości wirtualne zachowują się jak metody abstrakcyjne, z wyjątkiem różnic w składni deklaracji i wywołania.

  • Użycie modyfikatora wirtualnego na właściwości statycznej jest błędem.
  • Dziedziczoną właściwość wirtualną można zastąpić w klasie pochodnej, dołączając deklarację właściwości, która używa modyfikatora override.
Russ Cam
źródło
6

Nawet jeśli nie planujesz wyprowadzać z klasy, oznaczenie metody wirtualnej może być konieczne, aby mockować klasę. Niektóre frameworki do pozorowania pozwalają tylko na mockowanie metod wirtualnych. Należy zauważyć, że metody implementujące interfejs są niejawnie wirtualne.

Używam RhinoMocks, które ma to ograniczenie i właśnie z tego powodu zacząłem oznaczać moje metody jako wirtualne. Dla mnie jest to prawdopodobnie największy powód do korzystania z metod wirtualnych, ponieważ przypadki dziedziczenia są znacznie rzadsze.

tvanfosson
źródło
5

Metody wirtualne są podobne do metod abstrakcyjnych w klasach bazowych, z tym wyjątkiem, że ich implementacja w klasach pochodnych jest opcjonalna. Możesz również umieścić logikę w metodzie wirtualnej i zastąpić ją w klasach pochodnych.

cyklo
źródło
4

Krótkie pytanie, krótka odpowiedź! Zakwalifikuj swoją metodę jako „wirtualną”, jeśli myślisz, że będziesz dziedziczyć klasę, do której należy.

Dłuższa odpowiedź: „wirtualne umożliwia przesłonięcie, nadanie metodzie innego znaczenia w klasie pochodnej.

Stephane Halimi
źródło
3

Aby móc przesłonić to w dziedziczeniu klas.

Sprawdź wpis MSDN dla słowa kluczowego. To wyjaśnia to bardziej szczegółowo.

PHeiberg
źródło
1

Nie trzeba dodawać, że metody wirtualne przydają się, gdy kod próbuje przestrzegać zasady Open Closed

Przeczytaj więcej o zasadzie otwartej i zamkniętej tutaj , oryginalnym opracowaniu OCP wuja Boba.

Należy również pamiętać, że metody nie są domyślnie wirtualne w C # w przeciwieństwie do Java.

abhilash
źródło
1

Funkcje wirtualne to funkcje, które tak naprawdę nie istnieją. Klasa pochodna może modyfikować funkcję wirtualną, nadpisując ją. Funkcje wirtualne są jednym ze sposobów osiągnięcia polimorfizmu w czasie wykonywania

    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();
      }
    }
Lineesh K Mohan
źródło
Co masz na myśli mówiąc „tak naprawdę nie istnieje”? Czy mógłbyś podać referencje
Mubarek
To nie wygląda jak dziedziczenie C #. Te publicmodyfikatory dostępu Po class Ai class Bprzyczyny błędów w czasie kompilacji. Dostępność elementów członkowskich w klasie bazowej z klasy pochodnej jest określana indywidualnie z klasy bazowej (domyślnie członkowie są private).
Minh Tran
@Minh Tran - Tak, masz rację. To było dziedziczenie C ++. W każdym razie zredagowałem post.
Lineesh K Mohan
1

Środowisko wykonawcze odbywa się w czasie kompilacji.
Gdy deklarujesz metodę jako wirtualną, zadeklarowanie jej w klasie pochodnej wymaga dodania modyfikatora overridelub new.
możemy to zobaczyć, kiedy TrySpeak. Podanie dziecka i ojca, obaj nazywają Mów o ojcu, podczas gdy TryScreamwywołują każdą metodę.
Aby to zrozumieć, jest kilka rzeczy, które powinniśmy wiedzieć, w przypadku Child, Istnieją dwie Screammetody z klasy Child lub Father. Mogliśmy zadzwonić do Scream klasy Child lub Father. Ponieważ VirtaulModifier oznacza metodę, aby mogła być nadpisywana przez klasę pochodną, ​​co oznacza, że ​​nawet ta Screamjest wywoływana z klasy Ojca, jest zastępowana, byłoby inaczej, gdybyś użył nowego modyfikatora.

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();
    }
}
soulomoon
źródło
1

W języku C #, aby zastąpić metodę klasy bazowej w klasie pochodnej, musisz zadeklarować metodę klasy bazowej jako wirtualną, a metodę klasy pochodnej jako przesłonięcie, jak pokazano poniżej:

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

Można również mieszać ukrywanie metody i przesłanianie metody za pomocą słowa kluczowego virtual i new, ponieważ metoda klasy pochodnej może być jednocześnie wirtualna i nowa. Jest to wymagane, gdy chcesz dalej przesłonić metodę klasy pochodnej na następny poziom, ponieważ zastępuję metodę klasy B, Test () w klasie C, jak pokazano poniżej:

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

ZŁOTE SŁOWA: słowo kluczowe virtual służy do modyfikowania metody, właściwości, indeksatora lub zdarzenia zadeklarowanego w klasie bazowej i umożliwia zastąpienie ich w klasie pochodnej.

Słowo kluczowe override służy do rozszerzania lub modyfikowania metody wirtualnej / abstrakcyjnej, właściwości, indeksatora lub zdarzenia klasy bazowej do klasy pochodnej.

Słowo kluczowe new służy do ukrywania metody, właściwości, indeksatora lub zdarzenia klasy bazowej w klasie pochodnej.

CIESZYĆ SIĘ :-)

Rana Bhopale
źródło
-1

Ten link zapewni lepsze zrozumienie dzięki bardzo prostemu przykładowi https://stackoverflow.com/a/2392656/3373865

Anand Kumar Jha
źródło
1
To nie jest tylko odpowiedź zawierająca tylko łącze (prosimy o uwzględnienie treści posta, do którego prowadzi łącze, w odpowiedzi na wypadek zerwania linku), ale także o C ++, a nie C #. Czy obowiązują tu te same zasady?
Marks Polakovs