Ocultación de Métodos en C#

Ocultación de Métodos en C#. Una vez estudiado el modo en el que los métodos se intercambian información a través de parámetros, volvemos al repaso de posibles modificadores que puede preceder a la declaración de un método.

Ocultación de Métodos en C#

Ya hemos hablado de la herencia, esto es, de cómo una clase es capaz de obtener los miembros de una clase base. Sin embargo no sabemos cómo reimplementar en una clase heredada la funcionalidad de un miembro de la base. Para esto precisa­mente tenemos la instrucción new, teniendo lo siguiente:

using System;

public class Base {

public static void MetodoBase () {

Console.WriteLine (“Yo soy Base.MetodoBase ()”);

}

}

public class Heredada : Base {

public static void Main () {

MetodoBase ();

}

new public static void MetodoBase () {

Console.WriteLine (“Yo soy Heredada.MetodoBase ()”);

}

}

Tenemos dos clases, donde una hereda de la otra. La segunda además redefine el método MetodoBase() gracias al modifica­dor new. Al ejecutar el programa, se vería lo siguiente:

Yo soy Heredada .MetodoBase ( )

Lo que verifica que la redefinición ha sido un éxito. Si eliminamos el parámetro new el pro­grama seguiría compilando, pero obtendría­mos una advertencia:

New. cs ( 18 ) warning CS0108:

The keyword new is required on’ Heredada . MetodoBas e ‘ because it hides inherited member’ Base .MetodoBase ‘

Compilation succeeded – 1 warning(s) s )

El compilador nos ayuda a no ocultar métodos sin querer. Igualmente, si la clase Base no tuviera ninguna definición para MetodoBase(), el compilador también nos advertiría de que no estamos redefiniendo nada. Todo esto se puede complicar un poco más. Supongamos que tenemos una clase B que hereda de A, y una clase C que here­da de B. Pues bien, es posible redefinir un método de A en B, sin que C note el cambio, teniendo lo siguiente:

using System;

public class A {

public static void MetodoBase () {

Console.WriteLine (“Yo soy A.MetodoBase ()”);

}

}

public class B : A {

new prívate static void MetodoBase () {

Console.WriteLine (“Yo soy B.MetodoBase ()”);

}

}

public class C : B {

static void Main () {

MetodoBase ();

}

}

El método C imprimiría por pantalla “Yo soy A.MetodoBase ()” gracias a que en B hemos marcado la redefinición como priva­da, lo que la restringe a dicha clase. Si cam­biamos prívate por public, o hacemos la lla­mada dentro de BTérminos Básicos en la Computación (Parte 1)conseguiremos “Yo soy B.MetodoBase ()”. Tenemos una doble herencia anidada de clases en la que la ocul­tación de métodos es solamente parcial.

Métodos Virtuales

Una herencia sutilmente diferente pero parecida a la anterior ocurre con los méto­dos virtuales. En este caso, podemos cambiar 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 ( )

Fuente: Revista “Todo Programación”. Año 1. Número 6.

Share this Story
Load More Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Check Also

Programación Orientada a Objeto

Programación Orientada a Objeto. El propósito de un programador ...

Usamos cookies propias y de terceros para mostrar publicidad personalizada según su navegación. Si continua navegando consideramos que acepta el uso de cookies. OK Más información