viernes, 19 de febrero de 2010

Polimorfismo

Polimorfismo

A través de la herencia, una clase puede utilizarse como más de un tipo; puede utilizarse como su propio tipo, cualquier tipo base o cualquier tipo de interfaz si implementa interfaces. Esto se denomina polimorfismo. En C#, todos los tipos son polimórficos. Los tipos se pueden utilizar como su propio tipo o como una instancia de Object, porque cualquier tipo trata automáticamente a Object como tipo base.

El polimorfismo no sólo es importante para las clases derivadas, sino también para las clases base. Cualquiera que utilice la clase base podría, de hecho, estar utilizando un objeto de la clase derivada que se haya convertido en el tipo de clase base. Los diseñadores de una clase base pueden anticipar qué aspectos de su clase base cambiarán probablemente para un tipo derivado. Por ejemplo, es posible que una clase base para automóviles contenga un comportamiento sujeto a cambios si el automóvil en cuestión es un vehículo familiar o uno descapotable. Una clase base puede marcar esos miembros de clase como virtuales, lo cual permite que las clases derivadas que representan automóviles descapotables y vehículos familiares reemplacen ese comportamiento.

Para obtener más información, vea Herencia.

Información general sobre el polimorfismo
Cuando una clase derivada hereda de una clase base, obtiene todos los métodos, campos, propiedades y eventos de la clase base. Para cambiar los datos y el comportamiento de una clase base, existen dos opciones: se puede reemplazar el miembro base por un nuevo miembro derivado o se puede reemplazar un miembro base virtual.

Para reemplazar un miembro de una clase base por un nuevo miembro derivado, se requiere la palabra clave new. Si una clase base define un método, campo o propiedad, la palabra clave new se utiliza para crear una nueva definición de ese método, campo o propiedad en una clase derivada. La palabra clave new se coloca antes del tipo de valor devuelto de un miembro de clase que se reemplaza. Por ejemplo:

public class ClaseBase
{
public void DoWork() { }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}

public class ClaseDerivada : ClaseBase
{
public new void DoWork() { }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}


Cuando se utiliza la palabra clave new, se llama a los nuevos miembros de clase en lugar de los miembros de clase base que se han reemplazado. Esos miembros de clase base se denominan miembros ocultos. Aún es posible llamar a los miembros de clase ocultos si una instancia de la clase derivada se convierte en una instancia de la clase base. Por ejemplo:

ClaseDerivada B = new ClaseDerivada();
B.DoWork(); // Llama el metodo nuevo.

ClaseBase A = (ClaseBase)B;
A.DoWork(); // Llama el metodo viejo.


Para que una instancia de una clase derivada controle por completo un miembro de clase de una clase base, la clase base debe declarar ese miembro como virtual. Esto se consigue agregando la palabra clave virtual antes del tipo de valor devuelto del miembro. Una clase derivada tiene entonces la opción de utilizar la palabra clave override, en lugar de new, para reemplazar la implementación de la clase base por la propia. Por ejemplo:

public class ClaseBase
{
public virtual void DoWork() { }
public virtual int WorkProperty
{
get { return 0; }
}
}
public class ClaseDerivada : ClaseBase
{
public override void DoWork() { }
public override int WorkProperty
{
get { return 0; }
}
}


Los campos no pueden ser virtuales. Sólo los métodos, propiedades, eventos e indizadores pueden serlo. Cuando una clase derivada reemplaza un miembro virtual, se llama a ese miembro aunque se tenga acceso a una instancia de esa clase como instancia de la clase base. Por ejemplo:

ClaseDerivada B = new ClaseDerivada();
B.DoWork(); // Llama el metodo nuevo.

ClaseBase A = (ClaseBase)B;
A.DoWork(); // Tambien llama el metodo nuevo.


Los métodos y propiedades virtuales permiten hacer planes para una expansión futura. El hecho de llamar a un miembro virtual sin importar cuál es el tipo que el llamador utiliza proporciona a las clases derivadas la opción de cambiar completamente el comportamiento aparente de la clase base.

Los miembros virtuales siguen siendo virtuales de forma indefinida, independientemente de cuántas clases se hayan declarado en la clase que originalmente declaró el miembro virtual. Si la clase A declara un miembro virtual, la clase B deriva de A y la clase C deriva de B, la clase C hereda el miembro virtual y tiene la opción de reemplazarlo, independientemente de si la clase B declaró la sustitución de ese miembro. Por ejemplo:

public class A
{
public virtual void DoWork() { }
}

public class B : A
{
public override void DoWork() { }
}


public class C : B
{
public override void DoWork() { }
}


Una clase derivada puede detener la herencia virtual si la sustitución se declara como sellada. Para ello es necesario colocar la palabra clave sealed antes de la palabra clave override en la declaración del miembro de clase. Por ejemplo:

public class C : B
{
public sealed override void DoWork() { }
}


En el ejemplo anterior, el método DoWork ya no es virtual para ninguna clase derivada de C. Todavía es virtual para instancias de C, aunque se conviertan al tipo B o A. Los métodos sellados se pueden reemplazar por clases derivadas mediante la palabra clave new, como se muestra en el ejemplo siguiente:

public class D : C
{
public new void DoWork() { }
}


En este caso, si se llama a DoWork en D mediante una variable de tipo D, se llama al nuevo DoWork. Si se utiliza una variable de tipo C, B o A para tener acceso a una instancia de D, una llamada a DoWork seguirá las reglas de la herencia virtual y enrutará esas llamadas a la implementación de DoWork en la clase C.

Una clase derivada que ha reemplazado un método o propiedad todavía puede tener acceso al método o propiedad de la clase base utilizando la palabra clave base. Por ejemplo:

public class A
{
public virtual void DoWork() { }
}

public class B : A
{
public override void DoWork() { }
}


public class C : B
{
public override void DoWork()
{
// Llama a DoWork en B para obtener el comportamiento de B:
base.DoWork();

// El comportamiento de DoWork que especifica a C iria aqui:
// ...
}
}


Para obtener más información, vea base.

No hay comentarios.:

Publicar un comentario

Preguntas;Comentarios;Aportes;Criticas Positivas;Recomendaciones.