Herencia y Polimorfismo en CSharp

Page 1

UNIVERSIDAD DE CORDOBA

FACULTAD DE CIENCIAS BASICAS E INGENIERIAS

PROGRAMA INGENIERIA DE SISTEMAS

CURSO: Electiva de profundización I (desarrollo de software libre)

TEMA: Herencia y polimorfismo en C#.

DESCRIPCION: Desarrollo practico del tema de la herencia y el polimorfismo en C#,

abordando aspectos del lenguaje como la implementación de clases, áreas de visibilidad,

declaración de propiedades, sintaxis para definir la herencia, clases abstractas y métodos

polimórficos del tipos abstracto, virtual y sobre escrito usando para ello una aplicación de

consola. El documento presenta al respecto los pasos necesarios para crear, compilar y

ejecutar una aplicación de consola desde el entorno de desarrollo integrado (IDE)

MonoDevelop en Linux para el lenguaje C#.

OBJETIVO: Diseñar e implementar en el lenguaje C# una jerarquía de clases para

ejemplificar con una aplicación de consola los conceptos de herencia y polimorfismo en

este lenguaje integrando conceptos nuevos de orientación a objetos como el uso de

propiedades, especificando los pasos para construir, compilar y ejecutar la aplicación en

el entorno de desarrollo MonoDevelop.

PALABRAS CLAVES: Diseño de clases UML, Herencia y polimorfismo en C#, métodos

virtuales, abstractos y sobre escritos en C#, desarrollo de aplicaciones de consola en

MonoDevelop.

DESARROLLO: A continuación se presenta un diagrama de clases en el que se ilustra

una jerarquía de clases que permiten realizar las cuatro operaciones básicas entre dos

números enteros, empleado para ello una clase abstracta que será de clase padre y en la

que los dos números se modelan con el concepto de propiedad, además se presentara la

forma de trabajo de C# con relación a los métodos polimórficos y el llamado de métodos

de la clase padre desde métodos de la clase hija con el apuntador base.

Lic. Luis Roberto Olascoaga Surmay

Page 2

Diagrama de clases

El siguiente diagrama de clases ilustra las clases necesarias para el ejemplo con una

relación de herencia entre la clase padre o base TNumeros (que es abstracta), sus clases

hijas correspondientes a cada una de las cuatro operaciones básicas. Observe la

convención seguida en el diseño para expresar conceptos de orientación a objetos

propios del lenguaje C#, como son los casos de las propiedades, los métodos virtuales,

abstractos y sobre escrito. Note que el método Mostrar() de la clase padre TNumeros no

es obligado implementarlo por las clase hijas, por ello la clase TResta no lo hace aunque

las otras si lo sobre escribe, este detalle se explica mas adelante.

Lic. Luis Roberto Olascoaga Surmay

Page 3

Implementación.

1. Entrar en Monodevelop: Aplicaciones + programación + Monodevelop

El IDE (entorno de desarrollo integrado) de monodevelop es como sigue:

2. Crear una nueva solución: Archivo + nuevo + solución.

Lic. Luis Roberto Olascoaga Surmay

Page 4

Con lo que se despliega la siguiente ventana, en la que del nodo C# de la lista plantilla

seleccionamos la opción proyecto de consola. Seguidamente asigne un nombre al

proyecto (para el caso ejemplo1) y de forma opcional seleccione un directorio para

guardar el proyecto con sus archivos respectivos, usando para ello el botón examinar. Si

marca la opción crear subdirectorio de solución por separado, MonoDevelop creara un

directorio aparte con el mismo nombre de la solución para contener en ellos los archivos

de código fuente de clase (.cs) que cuelga dentro del directorio (raíz) de la solución, en el

que van los archivos de proyecto y configuración. Seguidamente pulse el botón adelante.

3. Posteriormente se presenta una ventana en la que puede añadir otros proyectos

adicionales a la solución, los cuales son completamente opcionales. Así por ejemplo

tenemos la opción para soporte GTK#, la cual es empleada por las aplicaciones que

tendrán una interfaz grafica de usuario (GUI) en donde desarrollamos con ventanas y

eventos. Igualmente vemos la opción para un proyecto de traducción, con el fin de

crear archivos necesarios que permitan cambiar durante la ejecución del programan el

Lic. Luis Roberto Olascoaga Surmay

Page 5

idioma de la interfaz del usuario, incluido los posibles mensajes de texto que se

presenten al usuario final.

Para este caso ninguna de estas opciones son necesarias y por ello no debe

marcarlas. En la ventana siguiente se observan estas opciones y se aprecia una

descripción bastante clara al respecto.

4. La siguiente pantalla ilustra el estado inicial de la solución, donde en el panel izquierdo

vemos el inspector de la solución, mostrando las referencias (ensamblados externos)

y las clases que componen el proyecto, para este caso el archivo principal Main.cs

que contiene la clase MainClass presentada en el panel de la derecha. En este se

aprecia que la definición de la clase se encuentra dentro de un nombre de espacio

(namespace) llamado ejemplo1, que es mismo nombre de la solución. La clase tiene

por defecto un único método que es público, estático (static), tipo void llamado Main y

que recibe por parámetro un vector de cadenas de caracteres (¿Qué representan

estos parámetros?).

Lic. Luis Roberto Olascoaga Surmay

Page 6

En este ejercicio no es necesario usar los nombres de espacio, por lo tanto en todos

los archivos de clase que crearemos incluido el de la clase principal, quitaremos la

declaración del nombre de espacio y la llave de apertura { y cierre de esta }. Antes de

ver el código de esta clase, construiremos otras clases con sus correspondientes

archivos de código fuente (.cs)

5. Anadir una nueva clase: Click derecho en el nombre de la solución (ejemplo1) + añadir

+ nuevo archivo.

6. En la siguiente ventana seleccione del panel de la izquierda la opción general, luego

del panel de la derecha marque clase vacía y finalmente ingrese el nombre de la

clase, para este caso será TNumeros. Finalmente pulse el botón nuevo.

Lic. Luis Roberto Olascoaga Surmay

Page 7

La pantalla de abajo ilustra el esqueleto de la clase TNumeros recién creada que

seguidamente procederemos a completar.

7. Implemente la clase TNumeros como indica en la pantalla de abajo, siguiendo la

sugerencia anteriormente señalada borrando el nombre de espacio. En C# el

constructor de una clase tiene el mismo nombre de la clase, una visibilidad

(normalmente publica) pero no se indica ningún tipo de retorno ni siquiera void. En la

implementación del constructor, se inicia los dos atributos a cero y se imprime un

mensaje indicando que se esta ejecutando el constructor de la clase padre, esto no es

necesario para la funcionalidad de la clase, solo se ha incluido para que usted

compruebe que constructores se utilizan en cada objeto inicializado. Esta clase como

características principales tiene que es abstracta por lo cual se precede su declaración

de la palabra reservada abstract. Esta clase declara dos atributos ambos de tipo

entero, para definir posteriormente con ellos dos propiedades del mismo tipo, tanto el

nombre del atributo como el de la propiedad solo obedecen a una convención; de

modo que a los atributos se les asigna un nombre que empieza por la letra F (de Field

o campo) y la propiedad tendrá el mismo nombre del atributo pero sin la letra F inicial

de éste.

Lic. Luis Roberto Olascoaga Surmay

Page 8

Como puede observarse en la imagen que sigue abajo, la definición de una propiedad

es similar a la de un método con la salvedad que no se indican paréntesis ni

parámetros para la propiedad. Aprecie además que los métodos que proveen el

encapsulado se incluyen en el cuerpo de la propiedad dentro de las llaves { } de esta.

Estos métodos como es habitual son el modificador (set) y el selector (get). Una

Lic. Luis Roberto Olascoaga Surmay

Page 9

propiedad en este orden de ideas, es entonces una forma de acceso indirecto a los

atributos, pues la propiedad se hace pública, el atributo relacionado con ella sigue

siendo privado y cuando se le asigna un valor a la propiedad este es “capturado” de

manera automática en la variable reservada llamada value, es asignado al atributo por

el método set. Cuando se requiere usar el valor de la propiedad, este valor se toma

del valor del atributo y se retorna con la sentencia return en la implementación del

método get. La clase tiene un método abstracto (que carece de implementación)

llamado Operacion() y otro virtual llamado Mostrar() que puede ser sobre escrito por

las clases hijas y que es usado para presentar en pantalla el resultado de la operación

entre los dos números.

8. Siguiendo los pasos 5 y 6 cree una nueva clase llamada TSuma que hereda de la

clase abstracta TNumeros; lo cual en la sintaxis de C# se indica poniendo dos puntos

(:) después del nombre de la clase hija (TSuma) seguido del nombre de la clase padre

(TNumeros), como se aprecia seguidamente:

En la implementación del constructor vemos la sentencia : base(), que significa que

antes de de ejecutar el constructor de la clase hija se va a ejecutar el constructor de la

clase padre. Este constructor en la clase hija solo muestra un mensaje indicando el

tipo de hijo. Por ello al crear un objeto de la clase TSuma se muestran dos mensajes,

el que ya indicamos en la clase padre seguido del que vemos en la presente pantalla.

Lic. Luis Roberto Olascoaga Surmay

Page 10

Al heredar de una clase abstracta, la clase TSuma debe implementar todos los

métodos abstractos heredados, para el caso se trata del método Operacion(), que

debe ser definido de idéntica forma a como viene de la clase padre; es decir con el

mismo nombre, misma visibilidad, idéntico tipo de resultado e igual lista de parámetros

tanto en tipo, orden y cantidad. Cuando una clase hija implementa un método

abstracto se debe usar la palabra reservada override (sobre escrito) en el momento

en que se declara el método y esta vez dicho método debe tener un cuerpo, una

implementación. Para el caso la clase TSuma simplemente retorna la suma de las dos

propiedades Num1 + Num2. ¿Por qué no se implemento como return

FNum1+FNum2?

El método Mostrar() en la clase padre fue declarado como virtual, lo que significa que

tiene una implementación pero puede ser sobre escrito por la clase hija, por ello

también esta precedido por la palabra reservada override. En la implementación del

método Mostrar() de la clase hija vemos que mostramos los dos números separados

por el signo de la operación y luego invocamos (ejecutamos) la implementación de la

clase padre para este mismo método, lo cual se hace usando nuevamente la palabra

reservada base, esta vez indicando el nombre del método de la clase padre que se

quiere ejecutar. Esta misma técnica se puede aplicar para cualquier caso en donde

requerimos ejecutar la implementación de un método de la clase padre desde la

implementación de un método de la clase hija, ojo sin importar que estos métodos no

sean los mismos (en cuanto a su nombre). ¿Qué sucede si en la implementación del

método mostrar() no pusiéramos base.?

Lic. Luis Roberto Olascoaga Surmay

Page 11

9. Siguiendo los pasos 5 y 6 cree una nueva clase llamada TResta y asegúrese de que

su implementación sea como sigue:

10. Construya las clases TProducto con el código como sigue:

Lic. Luis Roberto Olascoaga Surmay

Page 12

11. Construya las clases TCociente e impleméntela como sigue:

12. Pase al archivo Main.cs y asegúrese de que la implementación de la clase principal

(MainClass) quede como sigue:

En esta clase vemos que los métodos son estáticos (static) (¿Por qué ambos deben

ser estáticos?). El primero de ellos –el método Ejecutar()­ recibe por parámetro una

instancia (objeto) de la clase abstracta TNumeros (¿Por qué si se supone que una Lic. Luis Roberto Olascoaga Surmay

Page 13

clase abstracta por definición no puede ser instanciada?), a este objeto se le asigna

valores a sus dos propiedades pidiendo estos por consola y leyéndolos por teclado,

haciendo la conversión de la cadena de caracteres recibida del método

Console.ReadLine() usando el método estático Parse() del tipo int. (¿Acaso int no es

un tipo de datos primitivo y por qué entonces tiene métodos?). Finalmente se llama al

método mostrar.

En cuanto a la implementación del método Main vemos que se hacen llamados del

método Ejecutar() pasando instancias inicializadas con new y el constructor respectivo

de cada clase hija (¿Por qué se puede pasar una instancia de clase hija en un

parámetro cuyo tipo es clase padre?)

13. Para compilar el programa vaya por la opción construir + construir solucion o pulse la

tecla F8.

14. Para ejecutar el programa, como es de consola primero entre por la opción proyecto +

opciones como si indica aquí:

Lic. Luis Roberto Olascoaga Surmay

Page 14

15. En la ventana desplegada haga click en el nodo ejecutar del panel de la izquierda y

luego maque la casilla de verificación etiquetada como ejecutar en una consola

externa. Esto se hace para que el programa ejecute la sentencia Console.ReadLine()

de forma correcta. Finalmente pulse el botón aceptar.

16. Para ejecutar el programa ahora pulse el botón depurar o vaya por la opción ejecutar

+ ejecutar o pulse la tecla F5.

Lic. Luis Roberto Olascoaga Surmay

Page 15

Actividad propuesta.

Como complemente del anterior ejercicio desarrolle las siguientes actividades.

1. Resuelva con sustentación las preguntas realizadas a lo largo de los apartados

anteriores.

2. Que papel cumple el puntero this a nivel de la implementación y el llamado de

constructores sobre cargados desde otros constructores de la misma clase?. Ilustre

con un ejemplo.

3. Plantee una solución posible para el caso en que desde la implementación de un

constructor de una clase hija requiriéramos ejecutar un constructor de la clase padre

pero después de haber ejecutado parte o todo el código propio del constructor de la

clase hija. Tome en cuenta que el uso de base a nivel del constructor de la clase hija

no sirve en esta situación, pues el uso de este sugiere una llamada implícita del

constructor de la clase padre antes de ejecutar la primera instrucción del constructor

de la clase hija. Realice un ejemplo que implemente y demuestre que la solución

propuesta funciona correctamente.

4. Diseñe e incluya en el diagrama las clases necesarias para ampliar la funcionalidad de

la aplicación creando e implementando dichas clases, de modo que esta permita:

a. Calcular el MCD de dos números enteros.b. Calcular el MCM de dos números enteros.

c. Representar un número complejo con su parte real y su parte imaginaria,

suponiendo que ambas están dadas por un número entero. Se hace necesario

contar con un método que imprima el numero complejo de la forma binomial,

por ejemplo 3 + 4i.

d. Calcular la suma de los términos de la sucesión de fibonacci comprendidos

entre dos términos de los que se conoce su orden o posición (ojo no el valor

del termino), por ejemplo la suma de los términos que van del 3º al 10º (note

que no se indica el valor del termino sino su posición, el valor debe ser

calculado durante la operación).

Lic. Luis Roberto Olascoaga Surmay

Publicaciones Similares