Polimorfismo (Guía de programación de C#)Polymorphism (C# Programming Guide)

El polimorfismo suele considerarse el tercer pilar de la programación orientada a objetos, después de la encapsulación y la herencia.Polymorphism is often referred to as the third pillar of object-oriented programming, after encapsulation and inheritance. Polimorfismo es una palabra griega que significa "con muchas formas" y tiene dos aspectos diferentes:Polymorphism is a Greek word that means "many-shaped" and it has two distinct aspects:

  • En tiempo de ejecución, los objetos de una clase derivada pueden ser tratados como objetos de una clase base en lugares como parámetros de métodos y colecciones o matrices.At run time, objects of a derived class may be treated as objects of a base class in places such as method parameters and collections or arrays. Cuando se produce este polimorfismo, el tipo declarado del objeto ya no es idéntico a su tipo en tiempo de ejecución.When this polymorphism occurs, the object's declared type is no longer identical to its run-time type.
  • Las clases base pueden definir e implementar métodos virtuales, y las clases derivadas pueden invalidarlos, lo que significa que pueden proporcionar su propia definición e implementación.Base classes may define and implement virtual methods, and derived classes can override them, which means they provide their own definition and implementation. En tiempo de ejecución, cuando el código de cliente llama al método, CLR busca el tipo en tiempo de ejecución del objeto e invoca esa invalidación del método virtual.At run-time, when client code calls the method, the CLR looks up the run-time type of the object, and invokes that override of the virtual method. En el código fuente puede llamar a un método en una clase base y hacer que se ejecute una versión del método de la clase derivada.In your source code you can call a method on a base class, and cause a derived class's version of the method to be executed.

Los métodos virtuales permiten trabajar con grupos de objetos relacionados de manera uniforme.Virtual methods enable you to work with groups of related objects in a uniform way. Por ejemplo, supongamos que tiene una aplicación de dibujo que permite a un usuario crear varios tipos de formas en una superficie de dibujo.For example, suppose you have a drawing application that enables a user to create various kinds of shapes on a drawing surface. En tiempo de compilación, no sabe qué tipos específicos de formas creará el usuario.You do not know at compile time which specific types of shapes the user will create. Sin embargo, la aplicación tiene que realizar el seguimiento de los distintos tipos de formas que se crean, y tiene que actualizarlos en respuesta a las acciones del mouse del usuario.However, the application has to keep track of all the various types of shapes that are created, and it has to update them in response to user mouse actions. Para solucionar este problema en dos pasos básicos, puede usar el polimorfismo:You can use polymorphism to solve this problem in two basic steps:

  1. Crear una jerarquía de clases en la que cada clase de forma específica deriva de una clase base común.Create a class hierarchy in which each specific shape class derives from a common base class.
  2. Usar un método virtual para invocar el método apropiado en una clase derivada mediante una sola llamada al método de la clase base.Use a virtual method to invoke the appropriate method on any derived class through a single call to the base class method.

Primero, cree una clase base llamada Shape y clases derivadas como Rectangle, Circle y Triangle.First, create a base class called Shape, and derived classes such as Rectangle, Circle, and Triangle. Dé a la clase Shape un método virtual llamado Draw e invalídelo en cada clase derivada para dibujar la forma determinada que la clase representa.Give the Shape class a virtual method called Draw, and override it in each derived class to draw the particular shape that the class represents. Cree un objeto List<Shape> y agréguele una instancia de Circle, Triangle y Rectangle.Create a List<Shape> object and add a Circle, Triangle, and Rectangle to it.

public class Shape
{
    // A few example members
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }

    // Virtual method
    public virtual void Draw()
    {
        Console.WriteLine("Performing base class drawing tasks");
    }
}

public class Circle : Shape
{
    public override void Draw()
    {
        // Code to draw a circle...
        Console.WriteLine("Drawing a circle");
        base.Draw();
    }
}
public class Rectangle : Shape
{
    public override void Draw()
    {
        // Code to draw a rectangle...
        Console.WriteLine("Drawing a rectangle");
        base.Draw();
    }
}
public class Triangle : Shape
{
    public override void Draw()
    {
        // Code to draw a triangle...
        Console.WriteLine("Drawing a triangle");
        base.Draw();
    }
}

Para actualizar la superficie de dibujo, use un bucle foreach para iterar por la lista y llamar al método Draw en cada objeto Shape de la lista.To update the drawing surface, use a foreach loop to iterate through the list and call the Draw method on each Shape object in the list. Aunque cada objeto de la lista tenga un tipo declarado de Shape, se invocará el tipo en tiempo de ejecución (la versión invalidada del método en cada clase derivada).Even though each object in the list has a declared type of Shape, it's the run-time type (the overridden version of the method in each derived class) that will be invoked.

// Polymorphism at work #1: a Rectangle, Triangle and Circle
// can all be used whereever a Shape is expected. No cast is
// required because an implicit conversion exists from a derived
// class to its base class.
var shapes = new List<Shape>
{
    new Rectangle(),
    new Triangle(),
    new Circle()
};

// Polymorphism at work #2: the virtual method Draw is
// invoked on each of the derived classes, not the base class.
foreach (var shape in shapes)
{
    shape.Draw();
}
/* Output:
    Drawing a rectangle
    Performing base class drawing tasks
    Drawing a triangle
    Performing base class drawing tasks
    Drawing a circle
    Performing base class drawing tasks
*/

En C#, cada tipo es polimórfico porque todos los tipos, incluidos los definidos por el usuario, heredan de Object.In C#, every type is polymorphic because all types, including user-defined types, inherit from Object.

Introducción al polimorfismoPolymorphism overview

Miembros virtualesVirtual members

Cuando una clase derivada hereda de una clase base, obtiene todos los métodos, campos, propiedades y eventos de la clase base.When a derived class inherits from a base class, it gains all the methods, fields, properties, and events of the base class. El diseñador de la clase derivada tiene diferentes opciones para el comportamiento de los métodos virtuales:The designer of the derived class has different choices for the behavior of virtual methods:

  • La clase derivada puede invalidar los miembros virtuales de la clase base, y definir un comportamiento nuevo.The derived class may override virtual members in the base class, defining new behavior.
  • La clase derivada hereda el método de clase base más cercano sin invalidarlo, para conservar el comportamiento existente, pero permite que más clases derivadas invaliden el método.The derived class inherit the closest base class method without overriding it, preserving the existing behavior but enabling further derived classes to override the method.
  • La clase derivada puede definir una nueva implementación no virtual de esos miembros que oculte las implementaciones de la clase base.The derived class may define new non-virtual implementation of those members that hide the base class implementations.

Una clase derivada puede invalidar un miembro de la clase base si este se declara como virtual o abstracto.A derived class can override a base class member only if the base class member is declared as virtual or abstract. El miembro derivado debe usar la palabra clave override para indicar explícitamente que el propósito del método es participar en una invocación virtual.The derived member must use the override keyword to explicitly indicate that the method is intended to participate in virtual invocation. El siguiente fragmento de código muestra un ejemplo:The following code provides an example:

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

Los campos no pueden ser virtuales; solo pueden serlo los métodos, propiedades, eventos e indizadores.Fields cannot be virtual; only methods, properties, events, and indexers can be virtual. Cuando una clase derivada invalida un miembro virtual, se llama a ese miembro aunque se acceda a una instancia de esa clase como una instancia de la clase base.When a derived class overrides a virtual member, that member is called even when an instance of that class is being accessed as an instance of the base class. El siguiente fragmento de código muestra un ejemplo:The following code provides an example:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Also calls the new method.

Los métodos y propiedades virtuales permiten a las clases derivadas extender una clase base sin necesidad de usar la implementación de clase base de un método.Virtual methods and properties enable derived classes to extend a base class without needing to use the base class implementation of a method. Para obtener más información, consulte Control de versiones con las palabras clave Override y New.For more information, see Versioning with the Override and New Keywords. Una interfaz proporciona otra manera de definir un método o conjunto de métodos cuya implementación se deja a las clases derivadas.An interface provides another way to define a method or set of methods whose implementation is left to derived classes. Para más información, vea Interfaces.For more information, see Interfaces.

Ocultación de miembros de clase base con miembros nuevosHide base class members with new members

Si quiere que la clase derivada tenga un miembro con el mismo nombre que el de un miembro de una clase base, puede usar la palabra clave new para ocultar el miembro de clase base.If you want your derived class to have a member with the same name as a member in a base class, you can use the new keyword to hide the base class member. La palabra clave new se coloca antes que el tipo devuelto del miembro de la clase que se está reemplazando.The new keyword is put before the return type of a class member that is being replaced. El siguiente fragmento de código muestra un ejemplo:The following code provides an example:

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

public class DerivedClass : BaseClass
{
    public new void DoWork() { WorkField++; }
    public new int WorkField;
    public new int WorkProperty
    {
        get { return 0; }
    }
}

Se puede acceder a los miembros de la clase base ocultos desde el código de cliente si se convierte la instancia de la clase derivada en una instancia de la clase base.Hidden base class members may be accessed from client code by casting the instance of the derived class to an instance of the base class. Por ejemplo:For example:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Calls the old method.

Evasión de que las clases derivadas invaliden los miembros virtualesPrevent derived classes from overriding virtual members

Los miembros virtuales siguen siendo virtuales con independencia de cuántas clases se hayan declarado entre el miembro virtual y la clase que originalmente lo haya declarado.Virtual members remain virtual, regardless of how many classes have been declared between the virtual member and the class that originally declared it. Si la clase A declara un miembro virtual y la clase B deriva de A, y la clase C de B, la clase C hereda el miembro virtual y puede invalidarlo, independientemente de que la clase B haya declarado una invalidación para ese miembro.If class A declares a virtual member, and class B derives from A, and class C derives from B, class C inherits the virtual member, and may override it, regardless of whether class B declared an override for that member. El siguiente fragmento de código muestra un ejemplo:The following code provides an example:

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

Una clase derivada puede detener la herencia virtual al declarar una invalidación como sealed.A derived class can stop virtual inheritance by declaring an override as sealed. Para detener la herencia, es necesario colocar la palabra clave sealed antes de la palabra clave override en la declaración del miembro de la clase.Stopping inheritance requires putting the sealed keyword before the override keyword in the class member declaration. El siguiente fragmento de código muestra un ejemplo:The following code provides an example:

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

En el ejemplo anterior, el método DoWork ya no es virtual para ninguna clase que se derive de C.In the previous example, the method DoWork is no longer virtual to any class derived from C. Sigue siendo virtual para las instancias de C, aunque se conviertan al tipo B o al tipo A.It's still virtual for instances of C, even if they're cast to type B or type A. Los métodos sellados se pueden reemplazar por clases derivadas mediante la palabra clave new, como se muestra en el ejemplo siguiente:Sealed methods can be replaced by derived classes by using the new keyword, as the following example shows:

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

En este caso, si se llama a DoWork en D con una variable de tipo D, se llama a la nueva instancia de DoWork.In this case, if DoWork is called on D using a variable of type D, the new DoWork is called. Si se usa una variable de tipo C, B o A para acceder a una instancia de D, la llamada a DoWork seguirá las reglas de herencia virtual y enrutará esas llamadas a la implementación de DoWork en la clase C.If a variable of type C, B, or A is used to access an instance of D, a call to DoWork will follow the rules of virtual inheritance, routing those calls to the implementation of DoWork on class C.

Acceso a miembros virtuales de clases base desde clases derivadasAccess base class virtual members from derived classes

Una clase derivada que ha reemplazado o invalidado un método o propiedad puede seguir accediendo al método o propiedad en la clase base usando la siguiente palabra clave base.A derived class that has replaced or overridden a method or property can still access the method or property on the base class using the base keyword. El siguiente fragmento de código muestra un ejemplo:The following code provides an example:

public class Base
{
    public virtual void DoWork() {/*...*/ }
}
public class Derived : Base
{
    public override void DoWork()
    {
        //Perform Derived's work here
        //...
        // Call DoWork on base class
        base.DoWork();
    }
}

Para obtener más información, vea base.For more information, see base.

Nota

Se recomienda que las máquinas virtuales usen base para llamar a la implementación de la clase base de ese miembro en su propia implementación.It is recommended that virtual members use base to call the base class implementation of that member in their own implementation. Dejar que se produzca el comportamiento de la clase base permite a la clase derivada concentrarse en implementar el comportamiento específico de la clase derivada.Letting the base class behavior occur enables the derived class to concentrate on implementing behavior specific to the derived class. Si no se llama a la implementación de la clase base, depende de la clase derivada hacer que su comportamiento sea compatible con el de la clase base.If the base class implementation is not called, it is up to the derived class to make their behavior compatible with the behavior of the base class.

En esta secciónIn this section

Vea tambiénSee also