¿Qué son los métodos virtuales?

81

¿Por qué declararía un método como "virtual"?

¿Cuál es el beneficio de usar virtual?

HerbalMart
fuente

Respuestas:

58

El Modificador virtual se usa para marcar que un método \ propiedad (ect) se puede modificar en una clase derivada usando el modificador de anulación .

Ejemplo:

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
fuente
45

Virtual permite que una clase heredada reemplace un método que luego usa la clase base.

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

Cuando ejecute el programa, su salida será:

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

Observe cómo, aunque Widget llamó al método Action () definido en el nivel Thingy, internamente Thingy llamó al método StepA () de Widget.

La respuesta básica es que da a los herederos de una clase más flexibilidad. Por supuesto, tienes que diseñar bien tu clase o podría causar estragos.

Ludington
fuente
23

Un método virtual es un tipo de método en el que las llamadas al método reales dependen del tipo de tiempo de ejecución del objeto subyacente.

Un método no virtual es un tipo de método en el que el método real llamado depende del tipo de referencia del objeto en el punto de invocación del método.

JaredPar
fuente
Esta debería ser una respuesta: virtual no se puede definir a través de los términos de modificación de la declaración. ¿En qué se diferencia entonces del método de ocultación?
SENya
13

Métodos virtuales en MSDN

La palabra clave virtual se usa para modificar un método o declaración de propiedad, en cuyo caso el método o la propiedad se denomina miembro virtual. La implementación de un miembro virtual puede ser cambiada por un miembro primordial en una clase derivada.

Cuando se invoca un método virtual, se comprueba el tipo de tiempo de ejecución del objeto para un miembro primordial. Se llama al miembro primordial de la clase más derivada, que podría ser el miembro original, si ninguna clase derivada lo ha reemplazado. (Para obtener más información sobre el tipo de tiempo de ejecución y la implementación más derivada, consulte 10.5.3 Métodos virtuales).

De forma predeterminada, los métodos no son virtuales. No puede anular un método no virtual.

No puede usar el modificador virtual con los siguientes modificadores:

anulación abstracta estática

Las propiedades virtuales se comportan como métodos abstractos, excepto por las diferencias en la sintaxis de declaración e invocación.

  • Es un error utilizar el modificador virtual en una propiedad estática.
  • Una propiedad virtual heredada se puede anular en una clase derivada al incluir una declaración de propiedad que utilice el modificador de anulación.
Russ Cam
fuente
6

Incluso si no planea derivar de la clase, marcar el método como virtual puede ser necesario para burlarse de la clase. Algunos marcos de burla solo le permiten burlarse de métodos virtuales. Tenga en cuenta que los métodos que implementan una interfaz son virtuales implícitamente.

Utilizo RhinoMocks que tiene esta restricción y he decidido marcar mis métodos como virtuales de forma predeterminada solo por esta razón. Para mí, esta es probablemente la razón más importante para utilizar métodos virtuales, ya que los casos en los que entra en juego la herencia son mucho menos frecuentes.

tvanfosson
fuente
5

Los métodos virtuales son similares a los métodos abstractos en clases base, excepto que su implementación en clases derivadas es opcional. También puede poner lógica en el método virtual y anularlos en clases derivadas.

ciclo
fuente
4

¡Una breve pregunta, una breve respuesta! Califique su método como "virtual" si cree que heredará de la clase a la que pertenece.

Una respuesta más larga: "virtual le permite anular, para dar otro significado a su método en una clase derivada.

Stephane Halimi
fuente
3

Para poder anularlo en clases heredadas.

Consulte la entrada de MSDN para la palabra clave. Eso lo explica más a fondo.

PHeiberg
fuente
1

No hace falta decir que los métodos virtuales son útiles cuando su código intenta cumplir con el principio abierto cerrado

Lea más sobre el principio abierto cerrado aquí , el documento técnico original de OCP del tío Bob.

Además, tenga en cuenta que los métodos no son virtuales de forma predeterminada en C # a diferencia de Java.

abhilash
fuente
1

Las funciones virtuales son las funciones que realmente no existen. La clase derivada puede modificar la función virtual anulándola. Las funciones virtuales son una de las formas de lograr el polimorfismo en tiempo de ejecución.

    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
fuente
¿Qué quieres decir con "realmente no existe"? ¿Podría proporcionar una referencia
Mubarek
Esto no parece una herencia de C #. Los publicmodificadores de acceso después class Ay class Bprovocan errores en tiempo de compilación. La accesibilidad de los miembros en la clase base de la clase derivada se especifica de forma individual desde la clase base (por defecto, los miembros lo son private).
Minh Tran
@Minh Tran - Sí, tienes razón. Esa fue la herencia de C ++. De todos modos, edité la publicación.
Lineesh K Mohan
1

El tiempo de ejecución tiene lugar durante el tiempo de compilación.
Cuando declara un método como virtual, declararlo en la clase derivada requiere que agregue un modificador overrideo new.
podemos ver eso cuando TrySpeak. Al pasar hijo y padre, ambos llaman a Hablar de padre, mientras TryScreamque llamarían a cada método.
Para entender esto, hay algunas cosas que debemos saber, en una instancia de Child. Hay dos Screammétodos de la clase Child o la clase Father. Podríamos llamar alScream clase para niños o para padres. Debido a que VirtaulModifier marca el método para que pueda ser reemplazado por la clase derivada, lo que significa que incluso Screamse llama desde la clase Father, se reemplaza, sería diferente si usa un nuevo modificador.

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
fuente
1

En C #, para anular el método de la clase base en la clase derivada, debe declarar el método de la clase base como virtual y el método de la clase derivada como anulado como se muestra a continuación:

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

También puede combinar la ocultación de métodos y la anulación de métodos utilizando la palabra clave virtual y nueva, ya que el método de una clase derivada puede ser virtual y nuevo al mismo tiempo. Esto es necesario cuando desea anular aún más el método de clase derivada en el siguiente nivel, ya que estoy anulando la Clase B, el método Test () en la Clase C, como se muestra a continuación:

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

PALABRAS DE ORO: La palabra clave virtual se utiliza para modificar un método, propiedad, indexador o evento declarado en la clase base y permitir que se anule en la clase derivada.

La palabra clave override se usa para extender o modificar un método, propiedad, indexador o evento virtual / abstracto de la clase base en una clase derivada.

La nueva palabra clave se utiliza para ocultar un método, propiedad, indexador o evento de la clase base en la clase derivada.

DISFRUTA :-)

Rana Bhopale
fuente
-1

Este enlace le proporcionará una mejor comprensión con un ejemplo muy sencillo https://stackoverflow.com/a/2392656/3373865

Anand Kumar Jha
fuente
1
Esta no es solo una respuesta de solo enlace (incluya el contenido de la publicación vinculada en su respuesta, en caso de que el enlace se rompa), sino también sobre C ++, no C #. ¿Se aplican los mismos principios aquí?
Marca Polakovs