Métodos Virtuales

Una herencia sutilmente diferente pero parecida a la anterior ocurre con los méto­dos virtuales. En este caso, podemos cam­biar el funcionamiento de un método “hacia atrás”. Anteriormente vimos como una clase heredada puede implementar su propio método. En este caso, lo que pode­mos conseguir es que la clase heredada afecte al funcionamiento del método en la clase base. Veamos el siguiente ejemplo:

using System;

public class Base { public void MetodoNormal () {

Console.WriteLine (”Soy Base.MetodoNormal ()”);} public virtual void MetodoVirtual () { Console.WriteLine (”Soy Base.MetodoVirtual ()”);}

}

public class Heredada : Base {

new public void MetodoNormal () {

Console.WriteLine (”Soy Heredada.MetodoNormal ()”);

}

public override void MetodoVirtual () {

Console.WriteLine (”Soy Heredada.MetodoVirtual ()”);

}

static void Main () {

Heredada claseHeredada = new Heredada ();

Base claseBase = claseHeredada;

claseBase.MetodoNormal ();

claseHeredada.MetodoNormal ();

claseBase.MetodoVirtual ();

claseHeredada.MetodoVirtual (); 

}

}

Si lo ejecutamos obtenemos lo siguiente:

Soy Base.MetodoNormal ()

Soy Heredada.MetodoNormal ()

Soy Heredada.MetodoVirtual ()

Soy Heredada.MetodoVirtual ()

Nótese como algo extraño sucede en la tercera línea. Mientras que en el código fuente la llamada se hace a la clase Base, el resultado es el de la clase heredada, cosa que no ocurre con el “método normal”. La culpa de este comportamiento la tiene la combinación de las palabras clave virtual y override, que declaran y redefinen respectivamente a los métodos virtuales. En este caso el método escogido no se corres­ponde con el que observa en el momen­to de la compilación, sino en el momento de la ejecución. Debemos fijarnos en que la definición de la instancia de la clase base se hace en términos de la clase heredada al comienzo del método principal. Vemos entonces como override hace un papel análogo a new, solo que se ocupa de métodos virtuales, que pueden variar la funcionalidad incluso de las clases bases.  Si la declaración de las instancias las cambia­mos por las siguientes:

Base claseBase = new Base ();

Heredada claseHeredada = new Heredada ();

Todo funcionará sin diferencias. Los métodos virtuales se comportarán como los demás. Lo divertido sucede cuando volvemos a considerar más de dos clases. ¿Qué ocurrirá en el siguiente ejemplo? using System;class A {public virtual void Metodo () {

Console.WriteLine (”Yo soy A.Metodo ()”);

}

}

class B : A {

public override void Metodo () {

Console.WriteLine (”Yo soy B.Metodo ()”);

}

}

class C : B {

new public virtual void Metodo () {

Console.WriteLine (”Yo soy C.Metodo ()”);

}

}

class D : C {

public override void Metodo () {

Console.WriteLine (”Yo soy D.Metodo ()”);

}

static void Main () {

D d = new D ();

A a = d;

B b = d;

C c = d;

a.Metodo ();

b.Metodo ();

c.Metodo ();

d.Metodo ();

} 

}

Hemos usado todas las combinaciones posibles. Primero declaramos un método vir­tual, luego lo redefinimos con override. En C se usa new y se vuelve a emplear virtual, y en D se cierra el ciclo y se utiliza de nuevo overri­de. A continuación creamos una instancia de la clase más baja en el nivel de herencia, y el resto de las instancias las hacemos depender de ella. Como siempre, termina­mos llamando a todos los métodos. ¿Qué ocurrirá? Si hemos seguido el razonamiento hasta aquí, encontraremos rápidamente la respuesta: las clases que contengan méto­dos virtuales perderán su funcionalidad y las demás no. El problema está en a.Metodo() ya que tenemos dos opciones, o bien se queda con el método de B o bien salta hasta D que es la instancia activa. El resultado final es el siguiente, esto es, la clase que se ocupa de la implementación es la más cercana en el árbol de herencias:

Yo soy B.Metodo ( )

Yo soy B.Metodo ( )

Yo soy D.Metodo ( )

Yo soy D.Metodo ( )

Leave a Reply