herencia y polimorfismo en csharp
Embed Size (px)
TRANSCRIPT

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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