[go: up one dir, main page]

Academia.eduAcademia.edu

Polimorfismo en c#

Teoría y ejemplos de polimorfismo en c#

Polimorfismo (Guía de programación de C#) Visual Studio 2013 Otras versiones Este tema aún no ha recibido ninguna valoración - Valorar este tema A menudo se hace referencia al polimorfismo como el tercer pilar de la programación orientada a objetos, tras la encapsulación y la herencia. El término polimorfismo es una palabra griega que significa "con muchas formas" y tiene dos aspectos que lo caracterizan: 1. En tiempo de ejecución, los objetos de una clase derivada se pueden tratar como objetos de una clase base en lugares como parámetros de método y colecciones o matrices. Cuando esto sucede, el tipo declarado del objeto ya no es idéntico a su tipo en tiempo de ejecución. 2. Las clases base pueden definir e implementar métodosvirtuales y las clases derivadas pueden invalidarlos, lo que significa que proporcionan su propia definición e implementación. 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 esta invalidación del método virtual. Así, en el código fuente puede llamar a un método de una clase base y provocar la ejecución de la versión de clase derivada del método. Los métodos virtuales permiten trabajar con grupos de objetos relacionados de una manera uniforme. Por ejemplo, suponga que dispone de una aplicación de dibujo que permite a un usuario crear varios tipos de formas en una superficie de dibujo. En tiempo de compilación no conoce los tipos específicos de formas que creará el usuario. Sin embargo, la aplicación tiene que realizar el seguimiento de los diferentes tipos de formas que se crean y tiene que actualizarlos como respuesta a las acciones del mouse del usuario. Puede utilizar el polimorfismo para resolver este problema en dos pasos básicos: 1. Cree una jerarquía de clases en la que cada clase de forma específica derive de una clase base común. 2. Utilice un método virtual para invocar el método adecuado de una clase derivada a través de una única llamada al método de clase base. En primer lugar, cree una clase base llamada Shape y clases derivadas como Rectangle, Circle y Triangle. Incluya en la clase Shape un método virtual llamado Draw e invalídelo en cada clase derivada para dibujar la forma determinada que representa la clase. Cree un objeto List<Shape> y agregue elementos Circle, Triangle y Rectangle a él. Para actualizar la superficie de dibujo, utilice un bucle foreach para recorrer en iteración la lista y llamar al método Draw en cada objeto Shape de la lista. Aunque cada objeto de la lista tiene un tipo declarado de Shape, es el tipo en tiempo de ejecución (la versión invalidada del método en cada clase derivada) el que se invocará. C# Copiar 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"); } } class Circle : Shape { public override void Draw() { // Code to draw a circle... Console.WriteLine("Drawing a circle"); base.Draw(); } } class Rectangle : Shape { public override void Draw() { // Code to draw a rectangle... Console.WriteLine("Drawing a rectangle"); base.Draw(); } } class Triangle : Shape { public override void Draw() { // Code to draw a triangle... Console.WriteLine("Drawing a triangle"); base.Draw(); } } class Program { static void Main(string[] args) { // 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. System.Collections.Generic.List<Shape> shapes = new System.Collections.Generic.List<Shape>(); shapes.Add(new Rectangle()); shapes.Add(new Triangle()); shapes.Add(new Circle()); // Polymorphism at work #2: the virtual method Draw is // invoked on each of the derived classes, not the base class. foreach (Shape s in shapes) { s.Draw(); } // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* 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 tipos definidos por el usuario, heredan de Object. Información general sobre el polimorfismo Miembros virtuales Cuando una clase derivada hereda de una clase base, obtiene todos los métodos, campos, propiedades y eventos de la clase base. El diseñador de la clase derivada puede elegir si    invalida los miembros virtuales de la clase base hereda el método de clase base más parecido sin invalidarlo define una nueva implementación no virtual de los miembros que ocultan las implementaciones de la clase base Una clase derivada solo puede invalidar un miembro de la clase base si éste se declara como virtual o abstracto. El miembro derivado debe utilizar la palabra clave override para indicar explícitamente que el método va a participar en la invocación virtual. El código siguiente proporciona un ejemplo: C# Copiar 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 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. El código siguiente proporciona un ejemplo: C# Copiar 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 utilizar la implementación de clase base de un método. Para obtener más información, vea Control de versiones con las palabras clave Override y New (Guía de programación de C#). Una interfaz proporciona otra manera de definir un método o un conjunto de métodos cuya implementación se deja a las clases derivadas. Para obtener más información, vea Interfaces (Guía de programación de C#). Ocultar miembros de la clase base con nuevos miembros Si desea que el miembro derivado tenga el mismo nombre que un miembro de una clase base, pero no desea que participe en la invocación virtual, puede utilizar la palabra clave new. La palabra clave new se coloca antes del tipo de valor devuelto de un miembro de clase que se reemplaza. El código siguiente proporciona un ejemplo: C# Copiar 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; } } } Aún así, se puede tener acceso a los miembros de clase base ocultos desde el código de cliente si se la instancia de la clase derivada se convierte a una instancia de la clase base. Por ejemplo: C# Copiar DerivedClass B = new DerivedClass(); B.DoWork(); // Calls the new method. BaseClass A = (BaseClass)B; A.DoWork(); // Calls the old method. Evitar que las clases derivadas invaliden los miembros virtuales Los miembros virtuales siguen siendo virtuales de forma indefinida, independientemente de cuántas clases se hayan declarado entre el miembro virtual y la clase que originalmente lo declaró. 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. El código siguiente proporciona un ejemplo: C# Copiar public class A { public virtual void DoWork() { } } public class B : A { public override void DoWork() { } } Una clase derivada puede detener la herencia virtual si la invalidación se declara como sealed. Para ello es necesario incluir la palabra clave sealed antes de la palabra clave override en la declaración del miembro de clase. El código siguiente proporciona un ejemplo: C# Copiar 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. Sigue siendo virtual para las instancias de C, incluso si se convierten al tipo B o tipo A. Los métodos sellados se pueden reemplazar por clases derivadas mediante la palabra clave new, tal y como se muestra en el siguiente ejemplo: C# Copiar 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. Obtener acceso a miembros virtuales de la clase base desde clases derivadas 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. El código siguiente proporciona un ejemplo: C# Copiar 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. Nota Se recomienda que los miembros virtuales utilicen la palabra clave base para llamar a la implementación de la clase base de ese miembro en su propia implementación. Al permitir que se produzca el comportamiento de la clase base, se permite que la clase derivada se concentre en implementar el comportamiento específico de la clase derivada. Si no se llama a la implementación de la clase base, la compatibilidad del comportamiento de la clase derivada con el comportamiento de la clase base depende de la clase derivada. codigo fuente Aprendiz del NET Polimorfismo en c# Posted on julio 17, 2012 9 Polimorfismo es uno de los pilares de la programación orientada a objetos que mas se utiliza, lo único que es dejado de lado por los programadores en cuanto a su uso en las aplicaciones de negocios. En este post trataré de explicar su utilización en la programación. Primero tratemos de definir la palabra polimorfismo según una búsqueda por internet seria, Poli = muchos y Morfo = formas; si lo decimos literalmente seria “muchas formas”. En programación seria la capacidad que tiene una clase en convertirse en un nuevo objeto sin cambiar su esencia y luego volver al objeto origina de donde salió. Hay tres tipos de polimorfismo definamos cada uno: 1. polimorfismo por herencia: cuando se hereda de una clase normal y puedo convertirme en ella. 2. polimorfismos por abstracción: cuando puedo heredar de una clase abstracta y puedo convertirme en ella. 3. polimorfismo por interface: es la posibilidad que tenemos de implementar una interface y puedo convertirme en ella. Polimorfismo por Herencia: Este tipo de polimorfismo es el mas común que existe, y tiene la facultad de heredar de una clase padre y reemplazarla. En un proyecto de consola tendremos que crear estas tres clase: En la clase perro tenemos un método que solo nos devuelve un string. por otra parte las clases chihuahua y bulldog serán clases que heredaran el comportamiento de la clase perro. Ahora supongamos que estos dos perros son callejeros y viene el control de animales y los meta a la perrera. Esta perrera será un arreglo o Array en nuestro program, de la siguiente manera: En el arreglo perrera he metido cada uno de los perros que instanciamos, si lo corremos nos daría esto: El problema en esta ejecución es que aunque metimos distintos perros dentro de nuestra perrera como todos heredan de perros siempre dará el mismo mensaje. otra cosa que podemos observar es que en el foreach cuando ejecutamos el Console.WriteLine no nos da error esto se debe que al foreach le hemos dicho que todo esta basado en la clase perro, de esta forma el runtime sabe que para estar en la perrera hay que heredar de la clase perro en pocas palabras ser un perro. Cambiemos el comportamiento de los hijos; veamos supongamos que no todos los perros ladran de la misma forma el chihuahua ladra distinto que el bulldog. Para lograr esto la clase perro tiene que dejar o permitir que los hijos modifiquen el comportamiento; miremos como quedan las clases ya modificadas: Primero el método Ladrar es de tipo virtual esto me permitirá sobrescribir este método en los hijos, en las clases hijos usaremos la palabra clave override para sobrescribir el método virtual del padre. Si corremos la aplicación de consola nos dará esto: Cuando corrimos nuestro programa no se ejecuto el método del padre sino los cambios que hicimos en los hijos. Polimorfismo por Abstracción: Este tipo de polimorfismo se da con el uso de las clases abstractas. Pero que es una clase abstracta es aquella que además de lo normal que contiene una clase tiene comportamientos que si están definidos pero no implementados. Vemos lo siguiente que pasaría si en el ejemplo anterior nos vemos en la necesidad de implementar un comportamiento en los perros que sea dormir. El problema que no todos los perros duermen de la misma forma cada uno lo hace a su manera. Primero para lograr esto debemos de declarar la clase perro como abstracta y luego declarar el método dormir para luego implementarlo en las clases hijos, de esta forma: Como pueden ver hemos declarado la clase perro como abstracta y el método dormir también. Así que el Main del Program tendríamos que implementar el método abstracto de esta forma: si lo corremos nos daría este resultado: Hay que recordar que las clases abstractas no se pueden instanciar. Polimorfismo por Interface: Es uno de los polimorfismos mas importantes por que esta basado por contratos, que son los encargados de decirme que puedo hacer o no y como debo de hacerlo. En nuestro ejemplo vamos a crear un contrato que se llamara IPerro y definiremos los comportamientos que queremos en nuestra interfaz para luego implementarlo en nuestras clases hijos, de esta forma: Como pueden ver al convertir nuestra clase perro en una interfaz, tengo que especificar el comportamiento que quiero por parte de mi interfaz; en este caso Ladrar y Dormir. En el Main del Program tendríamos que cambiar esto. Una de las ventajas de hacer este tipo de polimorfismo es que oculta la implementación del comportamiento. Donde podemos ver este tipo de esquema es el WCF, por que el cliente solo puede ver el servicio y no la implementación del método. espero que te sirva este post… Implementación de Polimorfismo en C# a través de la sobrecarga de métodos. Fecha: 05/Ago/2005 (01 de Agosto de 2005) Autor: Jorge Barrientos (jbarrientos@tutopia.com) El presente articulo pretende ayudar a entender de la manera más sencilla y practica una de las técnicas con las que podemos implementar polimorfismo en nuestras clases creadas en .Net, como lo es la sobrecarga de métodos. El lenguaje utilizado para los ejemplos es C# sin embargo estos son fáciles de traducir a código Visual Basic. En primer lugar debemos comprender que el polimorfismo es una de las características mas poderosas e importantes de la programación orientada a objetos. La palabra polimorfismo es una palabra que significa “múltiples formas”, por lo tanto, podríamos definir en el ámbito de programación que el polimorfismo es “la capacidad de poder enviar un mismo mensaje a objetos totalmente diferentes, y que cada uno de estos objetos responda de manera diferente”. Antes que nada debemos comprender el concepto de clase base y clase derivada, la primera podríamos definirla como el padre y la segunda como el hijo que hereda del padre todos sus atributos y métodos a excepción de los definidos como privados (private), esto constituye lo que se denomina herencia de clase, que es la capacidad de poder agregar funcionalidad a una clase de la cual se hereda o extiende. ¿Que es sobrecarga de métodos? Podemos definir la sobrecarga de métodos, como la reescritura de un método de una clase base en una clase derivada. Para comenzar a entender como funciona la sobrecarga de métodos iniciaremos creando una clase base denominada Cuenta, que nos servirá de clase base para crear otras clases que heredaran de esta, las cuales veremos más adelante. public class Cuenta { private string idCuenta; // Número de la cuenta public Cuenta(string prmtIdCuenta) { this.idCuenta = prmtIdCuenta; System.Console.WriteLine( "Instancia creada para cuenta {0}",prmtIdCuenta); } public void CalcularIntereses() { System.Console.WriteLine("Cuenta.CalcularIntereses()"); } } Como podemos apreciar la clase Cuenta es muy sencilla pero posee lo necesario para nuestros propósitos, posee un atributo o dato de uso privado denominado idCuenta, posee un constructor que recibe como parámetro el id de la cuenta (prmtIdCuenta), el constructor nada mas asigna el parámetro al atributo idCuenta y escribe una línea en la consola que notifica la creación de una nueva instancia Cuenta. Además posee un método denominado CalcularIntereses() el cual escribirá en la consola el nombre del método, esto nos servirá para ubicarnos y saber que método estamos utilizando. Para empezar a comprender mejor sobre la sobrecarga, crearemos una nueva clase que hereda de la clase base Cuenta, y a esta nueva clase la denominaremos CuentaCorriente, la idea es poder crear clases para un sistema bancario hipotético, este banco operara con cuentas corrientes (Cheques) y de ahorros, para ambos casos los criterios o reglas del negocio para el calculo de intereses son diferentes, mientras para las primeras los intereses se realizan a favor del banco debido a sobregiros o en algunos casos (la excepción no la regla) pueden ser a favor del cliente, mientras que para las cuentas de ahorro será un calculo a favor del cliente, no entraremos en detalles sobre estos procesos ya que no es la idea del articulo, pero es un buen esquema que nos ayudara a comprender de manera fácil y practica lo que estamos estudiando. A continuación se detalla la definición de las clases CuentaCorriente y CuentaAhorro: public class CuentaCorriente : Cuenta { public CuentaCorriente(string prmtIdCuenta) : base(prmtIdCuenta) { } new public void CalcularIntereses() { System.Console.WriteLine( "CuentaCorriente.CalcularIntereses()"); } } public class CuentaAhorro : Cuenta { public CuentaAhorro(string prmtIdCuenta) : base(prmtIdCuenta) { } new public void CalcularIntereses() { System.Console.WriteLine( "CuentaAhorro.CalcularIntereses()"); } } Ahora exploraremos el código de la clase CuentaCorriente, en primer lugar podemos identificar que esta hereda de la clase Cuenta, también podemos apreciar un constructor que invoca el constructor de la clase base con el parámetro que contiene el número de cuenta. También podemos apreciar la sobrecarga o sobre escritura del método CalcularIntereses() y podemos identificar el uso de la palabra new, esta es necesaria para la definición del método de la clase derivada, si se omite no se registraran errores de compilación ni de ejecución debido a que implícitamente es definido como default, sin embargo el compilador subrayara el método y el IntelliSence enviara un warning advirtiendo que la palabra new es requerida (The keyword new is required on 'winAppTest.CuentaCorriente.CalcularIntereses()' because it hides inherited member 'winAppTest.Cuenta.CalcularIntereses()’), por lo tanto es buena practica siempre utilizarla. La misma explicación aplica para la clase CuentaAhorro. Ahora estamos en condiciones de poder realizar pruebas y ver como funcionan la sobrecarga en .Net. Para realizar nuestras pruebas crearemos una clase de testeo, denominada Test: public class Test { const string CUENTA = "100"; public static void Main(string[] args) { // Creamos instancia de clase base Cuenta cuenta = new Cuenta(CUENTA); // Creamos instancia de clase derivada CuentaCorriente cuentaCorriente = new CuentaCorriente(CUENTA); // Creamos instancia de clase derivada CuentaAhorro cuentaAhorro = new CuentaAhorro(CUENTA); // Invocamos método de la clase base cuenta.CalcularIntereses(); // Invocamos método de la clase derivada cuentaCorriente.CalcularIntereses(); // Invocamos método de la clase derivada cuentaAhorro.CalcularIntereses(); } } Ahora explicaremos este primer ejemplo, en el método Main podemos apreciar que creamos tres instancias a partir de las tres clases que hemos creado anteriormente, un objeto de la clase Cuenta (cuenta) y otros para la clases CuentaCorriente (cuentaCorriente) y CuentaAhorro (cuentaAhorro), para efectos de pruebas tenemos una constante para el número de la cuenta que se utiliza como parámetro para crear ambas instancias. Una vez creados los tres objetos invocamos el método CalcularIntereses() de todos los objetos. Al ejecutar esta clase obtenemos el siguiente resultado: Constructor Clase Base para cuenta 100 Constructor Clase Base para cuenta 100 Constructor Clase Base para cuenta 100 Cuenta.CalcularIntereses() CuentaCorriente.CalcularIntereses() CuentaAhorro.CalcularIntereses() Las primeras tres líneas escritas en la consola son las que el constructor de la clase base imprime en la consola (esto es debido a que las clases derivadas al momento de instanciarse ejecutan el método de la clase base), luego la tercera nos indica que el método que se ejecuta es el de la clase base Cuenta y por último tenemos la ejecución del método CalcularIntereses() de las clases derivadas. En este caso no hay mucho problema y trabaja bien siempre y cuando se tenga una referencia al objeto derivado, sin embargo cuando se tiene que realizar una referencia a una clase derivada a partir de una clase base, como se puede ejecutar un método de la clase derivada y evitar la ejecución del método de la clase base?, esto lo veremos a continuación. Ahora desarrollaremos cambios a las clases, simularemos un proceso unificado para calcular intereses tanto de cuentas corrientes como de ahorro. Para ello tendremos un proceso principal que simulara la carga de las cuentas en un arreglo y otro que procesara el cálculo de intereses de cada cuenta. La clase Cuenta quedara después de los cambios como se detalla a continuación: public class Cuenta { private string idCuenta; public Cuenta(string prmtIdCuenta) { this.idCuenta = prmtIdCuenta; System.Console.WriteLine( "Constructor Clase Base para cuenta {0}", prmtIdCuenta); } public void CalcularIntereses() { System.Console.WriteLine( "Cuenta.CalcularIntereses() efectuado para la cuenta {0}", this.idCuenta); } public string getIdCuenta() { return this.idCuenta; } } Para las clases CuentaCorriente y CuentaAhorro, solo se haran cambios al método CalcularIntereses(): // CuentaCorriente new public void CalcularIntereses() { System.Console.WriteLine( "CuentaCorriente.CalcularIntereses() efectuado para " + "la cuenta {0}", } getIdCuenta()); // CuentaAhorro new public void CalcularIntereses() { System.Console.WriteLine( "CuentaAhorro.CalcularIntereses() efectuado para " + "la cuenta {0}", getIdCuenta()); } Ahora crearemos una clase de prueba denominada TestPolimorfismo, la cual debe quedar de la siguiente forma: public class TestPolimorfismo { protected Cuenta[] cuentas; public static void Main(string[] args){ TestPolimorfismo test = new TestPolimorfismo(); test.cargaCuentas(); test.efectuarCalculoIntereses(); } public void cargaCuentas() { // Este proceso deberia de cargar las cuentas // de alguna base de datos. cuentas = new Cuenta[2]; // cuentas[0] = new CuentaCorriente("100"); cuentas[1] = new CuentaAhorro("200"); } public void efectuarCalculoIntereses() { for(int i = 0;i < cuentas.GetLength(0); i++) { cuentas[i].CalcularIntereses(); } } } Podemos apreciar que el método Main ejecuta el método de carga de las cuentas (cargaCuentas) y posteriormente el de calculo de Intereses (efectuarCalculoIntereses). Podemos observar que el método de carga de las cuentas crea dos instancias, una de la clase CuentaCorriente y otra de la clase CuentaAhorro. Sin embargo si ejecutamos la clase TestPolimorfismo el resultado es el siguiente: Constructor Clase Base para cuenta 100 Constructor Clase Base para cuenta 200 Cuenta.CalcularIntereses() efectuado para la cuenta 100 Cuenta.CalcularIntereses() efectuado para la cuenta 200 Esta ejecutando el método CalcularIntereses() de la clase base, algo que definitivamente no se desea, a este fenómeno se le denomina en ingles como early binding. Cuando el código compila, el compilador de C# observa la llamada al método CalcularIntereses() y determina la dirección en memoria necesaria para llegar cuando se ejecute la llamada. En nuestro caso será la ubicación en memoria del método Cuenta.CalcularIntereses(). Podemos determinar entonces que la llamada al método Cuenta.CalcularIntereses() es el problema que tenemos. Asi como existe un early binding, existe un late binding que permite que el compilador seleccione el método a ejecutar hasta que este se ejecute y no se determine en tiempo de compilación. Para forzar al compilador a que utilice el late binding, o que ejecute un método de una clase derivada a partir de una clase base, se utilizan dos palabras claves: virtual y override. Se debe usar virtual en el método de la clase base y override se debe colocar en la clase derivada. Por lo tanto para que nuestro ejemplo funcione, debemos de colocar el calificador virtual al método ClacularIntereses() de nuestra clase base Cuenta, y en las clases derivadas se le debe agregar el calificador override en la implementación del mismo método. Los métodos en todas las clases deben quedar como sigue: // Cuenta public virtual void CalcularIntereses() { System.Console.WriteLine( "Cuenta.CalcularIntereses() efectuado para la cuenta {0}", this.idCuenta); } // CuentaCorriente public override void CalcularIntereses() { System.Console.WriteLine( "CuentaCorriente.CalcularIntereses() efectuado para " + "la cuenta {0}", getIdCuenta()); } // CuentaAhorro public override void CalcularIntereses() { System.Console.WriteLine( "CuentaAhorro.CalcularIntereses() efectuado para " + "la cuenta {0}", getIdCuenta()); } Con este simple cambio, ejecutemos nuevamente la clase TestPolimorfismo, y obtendremos el resultado siguiente: Constructor Clase Base para cuenta 100 Constructor Clase Base para cuenta 200 CuentaCorriente.CalcularIntereses() efectuado para la cuenta 100 CuentaAhorro.CalcularIntereses() efectuado para la cuenta 200 Que es el resultado que esperábamos. Buenos amigos, espero que estos pequeños ejemplos les sirvan, como me ha servido a mi a comprender lo versátil y dinámica que puede ser la programación orientada a objetos, utilizando la característica del polimorfismo, sino la más fácil de entender, personalmente la considero la más poderosa. Espero pronto escribir un poco más sobre el tema, principalmente sobre la definición e implementación de interfaces, tema también relacionado con el polimorfismo. Hasta luego y no olvides calificar este articulo.