You are on page 1of 47

Programacin o Orientada a Objetos C#

Flix Gmez Mrmol e o a


3o Ingenier Informtica a a Julio de 2004

Indice general
Indice General 2. Clases y Objetos 2.1. Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1. Estructura . . . . . . . . . . . . . . . . . . . . . . . 2.1.2. Ocultacin de la informacin . . . . . . . . . . . . . o o 2.1.3. Relaciones entre clases: Cliente-Servidor y Herencia 2.1.4. Visibilidad . . . . . . . . . . . . . . . . . . . . . . . 2.2. Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3. Mensajes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1. Sintaxis. Notacin punto . . . . . . . . . . . . . . . . o 2.3.2. Semntica . . . . . . . . . . . . . . . . . . . . . . . . a 2.4. Semntica referencia versus semntica almacenamiento . . . a a 2.5. Creacin de objetos . . . . . . . . . . . . . . . . . . . . . . o 2.5.1. Destructores . . . . . . . . . . . . . . . . . . . . . . 2.6. Semntica de la asignacin e igualdad entre objetos . . . . . a o 2.7. Genericidad . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8. Denicin de una clase Lista Doblemente Enlazada . . . o 3. Dise o por Contrato: Asertos y Excepciones n 3.1. Contrato software . . . . . . . . . . . . . . . . 3.2. Clases y Correccin del software: Asertos . . o 3.3. Excepciones en C# . . . . . . . . . . . . . . . 3.3.1. Lanzamiento de excepciones . . . . . . 3.3.2. Bloques try . . . . . . . . . . . . . . . 3.3.3. Manejadores . . . . . . . . . . . . . . 3.4. Conversin de asertos en excepciones . . . . . o 4. Herencia 4.1. Introduccin . . . . . . . . . . . . . . . . . o 4.2. Doble aspecto de la herencia . . . . . . . . 4.3. Polimorsmo . . . . . . . . . . . . . . . . 4.3.1. Sobrecarga . . . . . . . . . . . . . 4.3.2. Regla de aplicacin de propiedades o 4.3.3. Estructuras de datos polimrcas . o 4.3.4. Operadores is y as . . . . . . . . 4.4. Ligadura Dinmica . . . . . . . . . . . . . a 4.5. Clases Diferidas . . . . . . . . . . . . . . . 4.5.1. Interfaces . . . . . . . . . . . . . . 4.6. Herencia, reutilizacin y extensibilidad del o 4.7. Herencia mltiple . . . . . . . . . . . . . . u 3 4 5 5 5 7 8 9 10 10 10 10 11 11 12 12 14 14 17 17 17 18 20 21 22 22 25 25 26 26 27 29 29 29 30 31 32 34 37

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . software . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

INDICE GENERAL

4.7.1. Problemas: Colisin de nombres y herencia repetida . . . . . . . . . . o 4.7.2. Ejemplos de utilidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.8. C#, Java y C++: Estudio comparativo . . . . . . . . . . . . . . . . . . . . . Indice de Figuras Indice de Tablas Indice de Cdigos o Bibliograf a

37 38 39 41 43 45 47

Tema 2

Clases y Objetos
2.1. Clases

Denicin 2.1 Una clase es una implementacin total o parcial de un tipo abstracto de o o dato (TAD). Sus caracter sticas ms destacables son que se trata de entidades sintcticas y que descria a ben objetos que van a tener la misma estructura y el mismo comportamiento.

2.1.1.

Estructura

Los componentes principales de una clase, que a partir de ahora llamaremos miembros, son: Atributos, que determinan una estructura de almacenamiento para cada objeto de la clase, y Mtodos, que no son ms que operaciones aplicables sobre los objetos. e a Ejemplo 2.1 La clase mostrada en el cdigo 2.1, llamada Luna, convierte a kilmetros la o o distancia de la Tierra a la Luna en millas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

// Distancia hasta la Luna convertida a kil metros o using System ; public class Luna { public static void Main () { int luna = 238857; int lunaKilo ; Console . WriteLine (" De la Tierra a la Luna = " + luna + " millas ") ; lunaKilo = ( int ) ( luna * 1.609) ; Console . WriteLine (" Kil metros = " o + lunaKilo + " km .") ; } } Cdigo 2.1: Clase Luna o

Tema 2. Clases y Objetos

Tipo short ushort int uint long ulong

Bytes 2 2 4 4 8 8

Rango de Valores (-32768, 32767) (0, 65535) (-2147483648, 2147483647) (0, 4294967295) (-9223372036854775808, 9223372036854775807) (0, 18446744073709551615)

Tabla 2.1: Tipos enteros primitivos Tipo float double decimal Bytes 4 8 16 Rango de Valores (3,4 1038 ) 7 d gitos signicativos (1,7 1038 ) de 15 a 16 d gitos signicativos 28 , 7,9 10+28 ) de 28 a 29 d (10 gitos signicativos Tabla 2.2: Tipos otantes primitivos Tipo byte ubyte bool char Bytes 1 1 1 2 Rango de Valores (-128,127) (0,255) {true, false} Tabla ASCII

Tabla 2.3: Otros tipos primitivos Tipos de datos primitivos Las tablas 2.1, 2.2 y 2.3 muestran los tipos primitivos soportados por C#. Para declarar un tipo consistente en un conjunto etiquetado de constantes enteras se emplea la palabra clave enum (por ejemplo, enum Edades {Flix = 21, Alex, Alberto = 15}). e Palabras reservadas La tabla 2.4 muestra las palabras reservadas de C#. abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false nally xed oat for foreach get goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed set short sizeof stackalloc static string struct switch this throw true try typeof unit ulong unchecked unsafe ushort using value virtual void volatile while

Tabla 2.4: Palabras reservadas

2.1 Clases

2.1.2.

Ocultacin de la informacin o o

En ocasiones conviene ocultar ciertas caracter sticas (atributos y/o mtodos) de una clase e al exterior. Por ejemplo, en una relacin entre clases de Cliente-Servidor, el servidor deber o a ocultar los aspectos de implementacin al cliente. o Para llevar a cabo esto, C# proporciona tres tipos de acceso: pblico, privado y protegido. u Un miembro con acceso privado (opcin por defecto) slo es accesible desde otros miemo o bros de esa misma clase, mientras que uno con acceso pblico es accesible desde cualquier u clase. Por ultimo, un miembro protegido slo es accesible por miembros de la misma clase o o bien por miembros de alguna de las subclases. Ejemplo 2.2 En el cdigo 2.2 se muestra un ejemplo de ocultacin de informacin, mediante o o o la clase Punto.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

public class Punto { private double x , y ; // O simplemente double x , y ; public void SetPunto ( double u , double v ) { x = u; y = v; } } . . . class Test { public void Prueba ( Punto w ) { . . . w . SetPunto (4.3 ,6.9) ; // Correcto w . x = 5.5; // Error sint ctico a . . . } } Cdigo 2.2: Ejemplo de Ocultacin de Informacin o o o A diferencia de C++, en C# es posible declarar un miembro como de slo lectura mediante o la palabra clave readonly. La diferencia entre readonly y const es que con la primera opcin la inicializacin tiene o o lugar en tiempo de ejecucin, mientras que con la segunda opcin la inicializacin se da en o o o tiempo de compilacin. o Una forma de simular el efecto de const mediante readonly es usando adems la palabra a clave static. Ejemplo 2.3 En el siguiente cdigo, n y m podr o amos decir que son estructuralmente equivalentes: public const n; public static readonly m; Otra prctica interesante consiste en declarar un atributo como privado y, mediante otro a atributo pblico tener acceso de lectura y/o escritura sobre el atributo privado. Para ello nos u valemos de los modicadores de acceso get y set. Ejemplo 2.4 En el cdigo 2.3 se muestra un ejemplo de ocultacin de informacin mediante o o o el uso de get y set. Obsrvese que el identicador value es siempre un objeto del mismo tipo que el atributo e que lo contiene.

Tema 2. Clases y Objetos

1 2 3 4 5 6 7 8 9 10 11 12 13

public class CuentaPalabras { private string m_file_output ; // Atributo privado public string OutFile // Atributo p blico asociado u { get { return m_file_output ; } // Acceso de lectura set { // Acceso de escritura if ( value . Length != 0 ) m_file_output = value ; } } } Cdigo 2.3: Otro ejemplo de Ocultacin de Informacin o o o

2.1.3.

Relaciones entre clases: Cliente-Servidor y Herencia

Un cliente de una clase debe ver a sta como un TAD, es decir, conocer su especicacin, e o pero sin importarle su implementacin (siempre que sta sea eciente y potente). o e El creador de la clase, en cambio, debe preocuparse de que dicha clase sea lo ms reutilia zable, adaptable, y eciente, as como que pueda ser usada por el mayor nmero de clientes u posible. Denicin 2.2 Una clase A se dice que es cliente de una clase B, si A contiene una declao racin en la que se establezca que cierta entidad (atributo, parmetro, variable local) e es de o a tipo B. Denicin 2.3 Una clase A se dice que hereda de otra clase B, si A es una versin especiao o lizada de B (herencia de especializacin), o bien si A es una implementacin de B (herencia o o de implementacin). o La gura 2.1.a muestra la relacin de clientela entre A y B, mientras que en la 2.1.b se o observa la relacin de herencia entre dichas clases. o

AB
(a)

B A
(b)

Figura 2.1: Clientela y Herencia entre A y B

Ejemplo 2.5 El siguiente cdigo muestra la relacin de clientela vista en la gura 2.1.a: o o class A { . . . B conta; . . . } Por su parte, el siguiente cdigo muestra la relacin de herencia mostrada en la gura o o 2.1.b: class A: B { . . . }

2.1 Clases

Por ultimo cabe decir que la herencia es una decisin de diseo ms comprometedora que o n a la clientela, pues en sta ultima se puede cambiar la implementacin de la clase que se emplea e o en el cliente, sin afectar a ste (en nuestro ejemplo, se puede modicar la implementacin de e o B sin que esto afecte a A).

2.1.4.

Visibilidad

Adems de lo comentado en el apartado 2.1.2 acerca de la ocultacin de informacin, en a o o esta seccin trataremos la cuestin de las clases anidadas. o o Denicin 2.4 Una clase anidada no es ms que una clase que se declara dentro de otra y o a que tiene visibilidad sobre todas las propiedades de los objetos de la clase que la incluye. Ejemplo 2.6 El cdigo 2.4 muestra un ejemplo de clases anidadas. o El resultado mostrado por pantalla ser a: IntAnidado(6) = 17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

public class Uno { public int c ; } public class Dos { public int c ; public class Tres { public int IntAnidado ( int e ) { Dos d = new Dos () ; Uno u = new Uno () ; u.c = 5 + e; d.c = c = e; return u . c + c ; } private int c ; } public Tres y ; } public class PruebaAnidada { public static void Main () { Dos x = new Dos () ; x . y = new Tres () ; Console . WriteLine (" IntAnidado (6) = " + IntAnidado (6) ) ; } } Cdigo 2.4: Ejemplo de Clases Anidadas o

10

Tema 2. Clases y Objetos

2.2.

Objetos

Denicin 2.5 Un objeto es una instancia de una clase, creada en tiempo de ejecucin y o o formada por tantos campos como atributos tenga la clase. Dichos campos son simples si corresponden a atributos de tipos primitivos (vase tablas e 2.1, 2.2 y 2.3), mientras que se dice que son compuestos si sus valores son subobjetos o referencias. Mientras exista, cada objeto se identica un vocamente mediante su identicador de objeto (oid). Una posible clasicacin de los objetos podr ser: o a Objetos externos: Son aquellos que existen en el dominio de la aplicacin. Por ejemplo, o Producto, Socio, Comercial, Descuento, ... Objetos software: Procedentes del anlisis: objetos del dominio. a Procedentes del diseo/implementacin: TDAs, patrones de diseo y GUI. n o n El estado de un objeto viene dado por la lista de pares atributo/valor de cada campo. Su modicacin y consulta se realiza mediante mensajes. o En cada instante de la ejecucin de una aplicacin Orientada a Objetos (en adelante, OO) o o existe un objeto destacado sobre el que se realiza algn tipo de operacin. Este objeto recibe u o el nombre de instancia actual. Para hacer referencia a la instancia actual en C# se emplea la palabra reservada this.

2.3.

Mensajes

Los mensajes son el mecanismo bsico de la computacin OO y consisten en la invocacin a o o de la aplicacin de un mtodo sobre un objeto. o e Constan de tres partes: objeto receptor, identicador del mtodo y los argumentos de ste e e ultimo.

2.3.1.

Sintaxis. Notacin punto o

Como se ha podido observar en algunos de los ejemplos vistos hasta ahora, la forma en que se invoca a un mtodo es mediante el operador punto, siguiendo una sintaxis como la e que a continuacin se muestra: o receptor.mtodo(argumentos) e

2.3.2.

Semntica a

La diferencia entre un mensaje y la invocacin a un procedimiento es que en ste ultimo o e todos los argumentos reciben el mismo trato, mientras que en los mensajes uno de esos argumentos, a saber, el objeto receptor, recibe un trato especial. Ejemplo 2.7 En el mensaje w.SetPunto(4.3,6.9) lo que se est queriendo decir es que se a aplique el mtodo SetPunto sobre el objeto receptor w, efectuando el correspondiente paso de e parmetros. a Cuando un mensaje no especica al objeto receptor la operacin se aplica sobre la instancia o actual. Si no se incluye nada, el paso de parmetros es por valor. Para especicar un paso de a parmetros por referencia se emplea la palabra clave ref delante del parmetro en cuestin. a a o

2.4 Semntica referencia versus semntica almacenamiento a a

11

2.4.

Semntica referencia versus semntica almacenamiento a a

En C# se tiene semntica referencia (gura 2.41 ) para cualquier entidad asociada a una a clase, aunque tambin existen los tipos primitivos (gura 2.22 ), como ya hemos visto. e Toda referencia puede estar, o bien no ligada (con valor null), o bien ligada a un objeto (mediante el operador new, o si se le asigna una referencia ya ligada). Pero ojo, la asignacin o no implica copia de valores sino de referencias ( Aliasing).

Figura 2.2: Variables en los lenguajes tradicionales

Figura 2.3: Variables tipo puntero en los lenguajes tradicionales

Figura 2.4: Variables en los lenguajes OO Algunas ventajas de los tipos referencia son: Son ms ecientes para manejar objetos. a Constituyen un soporte para denir estructuras de datos recursivas. Dan soporte al polimorsmo. Los objetos son creados cuando son necesarios. Se permite la comparticin de un objeto. o

2.5.

Creacin de objetos o

En C# existe un mecanismo expl cito de creacin de objetos mediante la instruccin de o o creacin new y los llamados mtodos constructores (que deben tener el mismo nombre que la o e clase en la que se denen). Estos constructores se encargan de inicializar los atributos con valores consistentes. Sin embargo tambin se pueden inicializar con unos valores por defecto, mediante los constructores e por defecto (aquellos que no tienen argumentos).
1 2

TETiempo de Ejecucin o TCTiempo de Compilacin o

12

Tema 2. Clases y Objetos

Ejemplo 2.8 El cdigo 2.5 muestra un ejemplo de una clase con un constructor y un conso tructor por defecto.
1 2 3 4 5 6 7 8 9 10 11 12

public class Contador { private int conta ; public public public { get set } public } Cdigo 2.5: Ejemplo de Constructores o Contador () { conta = 0; } // Constructor por defecto Contador ( int i ) { conta = i % 100; } // Constructor int Conta { return conta ; } { conta = value % 100; } void Click () { conta = ( conta + 1) % 100; }

2.5.1.

Destructores

Un destructor es un mtodo cuyo nombre es el nombre de la clase precedido de una tilde e . Mientras que los constructores s pueden tener modicadores de acceso, los destructores carecen de ellos. Cuando un objeto es recogido por el recolector de basura3 se llama impl citamente a su destructor. No obstante, en la mayor de los casos las clases no necesitan destructores, pues a con el recolector de basura es suciente para la nalizacin. o

2.6.

Semntica de la asignacin e igualdad entre objetos a o

Denicin 2.6 Una copia se dice que es supercial si se copian los valores de cada campo o del objeto origen en el objeto destino y ambos comparten referencias (gura 2.5).

Figura 2.5: Ejemplo de copia supercial Denicin 2.7 Una copia se dice que es profunda si se crea un objeto con una estructura o idntica al objeto origen y sin comparticin de referencias (gura 2.6). e o

Figura 2.6: Ejemplo de copia profunda


3

garbage collector

2.6 Semntica de la asignacin e igualdad entre objetos a o

13

Como ya se dijo anteriormente, la asignacin implica comparticin de referencias si se o o tiene semntica referencia, mientras que si se tiene semntica almacenamiento entonces se a a copian los valores. A este tipo de copia se le llama copia supercial y est soportada en C#. a Si se tiene semntica referencia y se realiza una copia supercial, los cambios hechos en a una variable tienen repercusin en su(s) correspondiente(s) copia(s). o Para evitar este efecto debemos realizar una copia profunda, lo cual puede llevarse a cabo, por ejemplo, implementando el mtodo Clone() de la interfaz ICloneable. e Ejemplo 2.9 El cdigo 2.6 muestra un ejemplo de una clase que implementa el mtodo o e Clone() de la interfaz ICloneable para conseguir una copia profunda.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

public class matrix : ICloneable { . . . public matrix ( int row , int col ) { m_row = ( row <= 0 ) ? 1 : row ; m_col = ( col <= 0 ) ? 1 : col ; m_mat = new double [ m_row , m_col ]; } public object Clone () { matrix mat = new matrix ( m_row , m_col ) ; for ( int i = 0; i < m_row ; ++ i ) for ( int j = 0; j < m_col ; ++ j ) mat . m_mat [i , j ] = m_mat [i , j ]; return mat ; } } Cdigo 2.6: Ejemplo de implementacin del mtodo Clone() o o e Nota.- La l nea 6 (equivalentemente la l nea 7) del cdigo 2.6 es equivalente al o siguiente cdigo: o if (row <= 0) m_row = 1; else m_row = row; Denicin 2.8 Dos variables se dice que son idnticas si ambas referencian al mismo objeto o e (gura 2.7). En C# esto se expresa de la siguiente forma: oa == ob

Figura 2.7: Ejemplo de variables idnticas e Denicin 2.9 Dos variables se dice que son iguales si ambas referencian a objetos con o valores iguales en sus campos (guras 2.5 y 2.7). En C# esto se expresa de la siguiente forma: oa.Equals(ob)

14

Tema 2. Clases y Objetos

De esta ultima denicin se deduce que siempre que haya identidad, tambin habr igual o e a dad supercial (gura 2.7), pero no necesariamente a la inversa (gura 2.5).

2.7.

Genericidad

C++ hace uso de plantillas, que son altamente ecientes y muy potentes, para implementar clases contenedoras genricas. Dichas plantillas estn propuestas para Java y C#, pero e a an estn en una fase experimental. u a C# consigue genericidad al estilo de Java, a saber, mediante el empleo de la clase ra z Object, con los consabidos inconvenientes: Necesidad de conversiones expl citas de tipo. Imposibilidad de asegurar homogeneidad.

2.8.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

Denicin de una clase Lista Doblemente Enlazada o

using System ; public class DListElement { public DListElement ( object val ) { data = val ; } public DListElement ( object val , DListElement d ) { data = val ; next = d ; d . previous = this ; } public DListElement Next { get { return next ; } set { next = value ; } } public DListElement Previous { get { return previous ; } set { previous = value ; } } public DListElement Data { get { return data ; } set { data = value ; } } private DListElement next , previous ; private object data ; } public class DList { public DList () { head = null ; } public DList ( object val ) { head = new DListElement ( val ) ; head . Next = head . Previous = null ; }

2.8 Denicin de una clase Lista Doblemente Enlazada o

15

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

public bool IsEmpty () { return head == null ; } public void Add ( object val ) { if ( IsEmpty () ) { head = new DListElement ( val ) ; head . Next = head . Previous = null ; } else { DListElement h = new DListElement ( val , head ) ; head . Previous = h ; head = h ; } } public object Front () { if ( IsEmpty () ) throw new System . Exception (" Empty DList ") ; return head . Data ; } public DListElement Find ( object val ) { DListElement h = head ; while ( h != null ) { if ( val . Equals ( h . Data ) ) break ; h = h . Next ; } return h ; } private DListElement Delete ( DListElement h ) { if ( h == null ) return null ; DListElement np = h . Next , pp = h . Previous ; if ( np != null ) np . Previous = pp ; else head = null ; if ( pp != null ) pp . Next = np ; return h . Next ; }

16

Tema 2. Clases y Objetos

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

public DListElement Delete ( object v ) { return Delete ( Find ( v ) ) ; } public override string ToString () { return ToStr ingRec ursive ( head ) ; } static string To String Recursive ( DListElement first ) { if ( first == null ) return ""; else return ( first . Data + "\ n ") + ToStr ingRec ursive ( first . Next ) ; } private DListElement head ; } Cdigo 2.7: Lista genrica doblemente enlazada o e A continuacin destacaremos algunos aspectos de este cdigo: o o Obsrvese el uso de get y set en las l e neas 13 a 20 (en mtodos declarados como pblicos) e u y las declaraciones privadas de las l neas 22 y 23. Es este un ejemplo de ocultacin de o informacin. o Otro ejemplo de ocultacin de informacin es la declaracin como privados de los mtoo o o e dos Delete y ToStringRecursive de las l neas 72 y 93, respectivamente. Podemos ver la implementacin de un constructor por defecto y un constructor en las o l neas 28 y 29, respectivamente, as como la sobrecarga de constructores en las l neas 4 y 6. Como se observa en la l nea 23 de este cdigo los datos almacenados en la lista son de o tipo object. Como ya se dijo anteriormente, as es como se consigue genericidad en C#. En la l nea 65 vemos un ejemplo de uso del mtodo Equals. El empleo del operador e == en esta l nea provocar una ejecucin incorrecta, distinta a la esperada. a o En la l nea 55 se ve un ejemplo del uso de excepciones, las cuales trataremos en el siguiente tema; y en la l nea 90 vemos cmo se sobrescribe el mtodo heredado ToString()4 . o e

Todo lo relacionado con la herencia se ver en profundidad en el tema 4 a

Tema 3

Dise o por Contrato: Asertos y n Excepciones


En este tema se describe el manejo de excepciones en C#. Las excepciones son habitualmente condiciones inesperadas de error que provocan la nalizacin del programa en el que o tienen lugar, con un mensaje de error. C#, sin embargo permite al programador intentar recuperarse frente a estas situaciones y as continuar con la ejecucin del programa. o

3.1.

Contrato software

Desde un punto de vista una excepcin se puede decir que se basa en el incumplimiento o del contrato software entre el cliente y el servidor de una clase. Segn este modelo, el usuario (cliente) debe garantizar que se cumplen las condiciones u necesarias para una correcta aplicacin del software. A estas condiciones se le conocen como o precondiciones. El proveedor (servidor), por su parte, debe garantizar que, si el cliente cumple con las precondiciones, el software realizar la tarea deseada satisfactoriamente. Si esto es as se dice a , que se cumplen las postcondiciones.

3.2.

Clases y Correccin del software: Asertos o

La correccin de los programas se puede ver en parte como una prueba de que la ejecucin o o terminar proporcionando una salida correcta, siempre que la entrada sea correcta. a Establecer una prueba formal completa de correccin del software es algo muy deseable, o pero por desgracia, no se lleva a cabo en la mayor de las ocasiones. De hecho, la disciplia na consistente en plantear asertos apropiados frecuentemente consigue que el programador advierta y evite bastantes errores de programacin que antes podr pasar desapercibidos. o an En C# la clase Debug contiene el mtodo Assert(), invocado de la siguiente manera: e Assert(expresin booleana,mensaje); o Si la expresin expresin booleana se evala como falsa, la ejecucin proporciona una o o u o salida de diagnstico, con el mensaje mensaje. Los asertos se habilitan deniendo la variable o DEBUG. Para acceder a dicha salida de diagnstico se emplean los listener. o Ejemplo 3.1 En el cdigo 3.1 se muestra un ejemplo del uso de asertos, as como del empleo o de listeners para visualizar los mensajes de diagnstico por pantalla. o

17

18

Tema 3. Dise o por Contrato: Asertos y Excepciones n

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

# define DEBUG using System ; using System . Diagnostics ; public class AssertSqrRoot { public static void Main () { Debug . Listeners . Clear () ; Debug . Listeners . Add ( new T e x t W r i t e rT r ac eL i st e ne r ( Console . Out ) ) ; double x ; string datos ; Console . WriteLine (" Introduzca un n mero real positivo :") ; u datos = Console . readLine () ; x = double . Parse ( datos ) ; Console . WriteLine ( x ) ; Debug . Assert ( x > 0 , " Valor no positivo ") ; Console . WriteLine (" La ra z cuadrada es " + Math . Sqrt ( x ) ) ; } } Cdigo 3.1: Ejemplo del uso de asertos o El uso de asertos reemplaza el uso ad hoc de comprobaciones condicionales con una metodolog ms uniforme. El inconveniente de los asertos es que no permiten una estrategia a a de reparacin o reintento para continuar con la ejecucin normal del programa. o o

3.3.

Excepciones en C#

C# contiene la clase estndar System.Exception, que es el objeto o la clase base de un a objeto lanzado por el sistema o por el usuario cuando ocurre un error en tiempo de ejecucin. o El mecanismo de manejo de excepciones en C# es sensible al contexto. Y dicho contexto no es ms que un bloque try, en el cual se declaran los manejadores (handlers) al nal del a mismo mediante la palabra clave catch. Un cdigo de C# puede alcanzar una excepcin en un bloque try mediante la expresin o o o throw. La excepcin es entonces tratada por alguno de los manejadores que se encuentran al o nal del bloque try. Ejemplo 3.2 El cdigo 3.2 muestra un ejemplo del uso de excepciones, con un bloque try, o la expresin throw y los manejadores denidos mediante la palabra clave catch. o
1 2 3 4 5 6 7 8

using System ; public class LanzaExcepcion { public static void Main () { try { double x ; string datos ;

3.3 Excepciones en C#

19

9 10 11 12 13 14 15 16 17 18 19 20 21

Console . WriteLine (" Introduzca un double :") ; datos = Console . readLine () ; x = double . Parse ( datos ) ; Console . WriteLine ( x ) ; if ( x > 0) throw ( new System . Exception () ) ; else Console . WriteLine (" La ra z cuadrada es " + Math . Sqrt ( x ) ) ; } catch ( Exception e ) { Console . WriteLine (" Lanzada excepci n " + e ) ; } o } } Cdigo 3.2: Ejemplo del uso de excepciones o La tabla 3.1 muestra algunas excepciones estndar en C#, mientras que en la tabla 3.2 a podemos observar las propiedades estndar que toda excepcin debe tener. a o SystemException ApplicationException ArgumentException ArgumentNullException ArgumentOutOfRangeException ArithmeticException DivideByZeroException IndexOutOfRangeException InvalidCastException IOException NullReferenceException OutOfMemoryException Clase base para las excepciones del sistema Clase base para que los usuarios proporcionen errores de aplicacin o Uno o ms argumentos son invlidos a a Pasado null no permitido Fuera de los valores permitidos Valor innito o no representable Auto-explicativa Indice fuera de los l mites del array Cast no permitido Clase base en el espacio de nombres System.IO para las excepciones de E/S Intento de referenciar a null Ejecucin fuera de la memoria heap o (montn) o

Tabla 3.1: Algunas Excepciones estndar a HelpLink InnerException Message StackTrace Source TargetSize Obtiene o establece un enlace a un chero de ayuda Obtiene la instancia de Exception que caus la excepcin o o Texto que describe el signicado de la excepcin o Traza de la pila cuando se llam a o la excepcin o Aplicacin u objeto que gener la o o excepcin o Mtodo que lanz la excepcin e o o

Tabla 3.2: Propiedades de las excepciones

20

Tema 3. Dise o por Contrato: Asertos y Excepciones n

3.3.1.

Lanzamiento de excepciones

Mediante la expresin throw se lanzan excepciones, las cuales deben ser objetos de la o clase Exception. El bloque try ms interno en el que se lanza una excepcin es empleado a o para seleccionar la sentencia catch que procesar dicha excepcin. a o Si lo que queremos es relanzar la excepcin actual podemos emplear un throw sin arguo mentos en el cuerpo de un catch. Esta situacin puede ser util si deseamos que un segundo o manejador llamado desde el primero realice un procesamiento ms exhaustivo de la excepcin a o en cuestin. o Ejemplo 3.3 El cdigo 3.3 muestra un ejemplo del relanzamiento de excepciones. o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

using System ; public class ReLanzaExcepcion { public static void LanzaMsg () { try { . . . throw new Exception (" Lanzada en LanzaMsg ") ; . . . } catch ( Exception e ) { . . . Console . WriteLine (" Primera captura " + e ) ; throw ; // Relanzamiento } } public static void Main () { try { . . . LanzaMsg () ; . . . } catch ( Exception e ) { Console . WriteLine (" Excepci n recapturada " + e ) ; } o } } Cdigo 3.3: Ejemplo del relanzamiento de excepciones o Conceptualmente, el lanzamiento de una excepcin pasa cierta informacin a los manejao o dores, pero con frecuencia stos no precisa de dicha informacin. Por ejemplo, un manejador e o que simplemente imprime un mensaje y aborta la ejecucin no necesita ms informacin de o a o su entorno. Sin embargo, el usuario probablemente querr informacin adicional por pantalla para a o seleccionar o ayudarle a decidir la accin a realizar por el manejador. En este caso ser o a apropiado empaquetar la informacin en un objeto derivado de una clase Exception ya o existente.

3.3 Excepciones en C#

21

Ejemplo 3.4 El cdigo 3.4 muestra un ejemplo del uso de objetos para empaquetar inforo macin que se pasa a los manejadores de excepciones. o El resultado mostrado por pantalla ser algo como: a Out of bounds with last char z
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

using System ; public class Stack { public char [] s = new char [100]; } public class StackError : Exception { public StackError ( Stack s , string message ) { st = s ; msg = message ; } public char TopEntry () { return st . s [99]; } public string Msg { set { msg = value ; } get { return msg ; }} private Stack st ; private string msg ; } public class StackErrorTest { public static void Main () { Stack stk = new Stack ; stk . s [99] = z ; try { throw new StackError ( stk ," Out of bounds ") ; } catch ( StackError se ) { Console . WriteLine ( se . Msg + " with last char " + se . TopEntry () ) ; } } } Cdigo 3.4: Uso de excepciones con ms informacin o a o

3.3.2.

Bloques try

Un bloque try es el contexto para decidir qu manejador invocar para cada excepcin e o que se dispara. El orden en el que se denen los manejadores determina el orden en el que se intenta invocar cada manejador que puede tratar la excepcin que haya saltado. o Una excepcin puede ser tratada por una manejador en concreto si se cumplen alguna de o estas condiciones: 1. Si hay una coincidencia exacta. 2. Si la excepcin lanzada ha sido derivada de la clase base del manejador. o Es un error listar los manejadores en un orden en el que se impida la ejecucin de alguno o de ellos, como muestra el siguiente ejemplo.

22

Tema 3. Dise o por Contrato: Asertos y Excepciones n

Ejemplo 3.5 Segn el siguiente cdigo: u o catch(ErrorClaseBase e) catch(ErrorClaseDerivada e) nunca se ejecutar el cuerpo del segundo catch, pues antes se encontrar una coincidencia a a con el primer catch, segn lo dicho en las condiciones anteriores. u

3.3.3.

Manejadores

La sentencia catch parece la declaracin de un mtodo con un solo argumento y sin valor o e de retorno. Incluso existe un catch sin ningn argumento, el cual maneja las excepciones no u tratadas por los manejadores que s tienen argumento. Cuando se invoca a un manejador a travs de una expresin throw, nos salimos del bloque e o try y automticamente se llama a los mtodos (incluidos los destructores) que liberan la a e memoria ocupada por todos los objetos locales al bloque try. La palabra clave finally despus de un bloque try introduce otro bloque que se ejecuta e despus del bloque try independientemente de si se ha lanzado una excepcin o no. e o

3.4.

Conversin de asertos en excepciones o

La lgica de las excepciones es ms dinmica ya que los manejadores pueden recibir ms o a a a informacin que los asertos, como ya hemos visto anteriormente. o Los asertos simplemente imprimen un mensaje por pantalla, mientras que con las excepciones, adems de imprimir ms informacin, se puede decidir (en algunos casos) entre a a o continuar la ejecucin del programa o abortarla de inmediato. o Ejemplo 3.6 El cdigo 3.5 es una reescritura del cdigo 3.1 que se muestra en el ejemplo o o 3.1 del uso de asertos, pero ahora mediante excepciones. En este ejemplo se ve cmo el programa hace uso del mecanismo de excepciones para o llamarse a s mismo recursivamente hasta que el usuario introduzca un nmero vlido para u a la entrada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

using System ; public class ExAssert { public static void MyAssert ( bool cond , string message , Exception e ) { if (! cond ) { Console . Error . WriteLine ( message ) ; throw e ; } } } class ExceptionSqrRoot { public static void ConsoleSqrt () { double x ; string datos ; Console . WriteLine (" Introduzca un double positivo :") ;

3.4 Conversin de asertos en excepciones o

23

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

datos = Console . readLine () ; x = double . Parse ( datos ) ; Console . WriteLine ( x ) ; try { ExAssert . MyAssert ( x > 0 , " Valor no positivo : x = " + x . ToString () , new Exception () ) ; Console . WriteLine (" La ra z cuadrada es " + Math . Sqrt ( x )); } catch ( Exception e ) { Console . WriteLine ( e ) ; ExceptionSqrRoot . ConsoleSqrt () ; // Se vuelve a intentar } } public static void Main () { Console . WriteLine (" Probando Ra ces Cuadradas ") ; ConsoleSqrt () ; } } Cdigo 3.5: Ejemplo del uso de excepciones en vez de asertos o

24

Tema 3. Dise o por Contrato: Asertos y Excepciones n

Tema 4

Herencia
4.1. Introduccin o

La herencia es un potente mecanismo para conseguir reutilizacin en el cdigo, consistente o o en derivar una nueva clase a partir de una ya existente. A travs de la herencia es posible e crear una jerarqu de clases relacionadas que compartan cdigo y/o interfaces. a o En muchas ocasiones distintas clases resultan ser variantes unas de otras y es bastante tedioso tener que escribir el mismo cdigo para cada una. Una clase derivada hereda la deso cripcin de la clase base, la cual se puede alterar aadiendo nuevos miembros y/o modicando o n los mtodos existentes, as como los privilegios de acceso. e Ejemplo 4.1 En la gura 4.1 se muestra un ejemplo de una jerarqu de clases. a

Figura 4.1: Jerarqu de clases a Denicin 4.1 Si B hereda de A entonces B incorpora la estructura (atributos) y comporo tamiento (mtodos) de A, pero puede incluir adaptaciones: e B puede aadir nuevos atributos. n B puede aadir nuevos mtodos. n e B puede redenir mtodos de A (bien para extender el mtodo original, bien para e e mejorar la implementacin). o B puede implementar un mtodo diferido en A. e 25

26

Tema 4. Herencia

La tabla 4.1 muestra los mtodos pblicos y protegidos de la clase object, ra en toda e u z jerarqu de clases de C#. a bool Equals(object o) void Finalize() int GetHashCode() Type GetType() object MemberwiseClone() bool ReferenceEquals (object a, object b) string ToString() Devuelve true si dos objetos son equivalentes, si no, devuelve false Equivalente a escribir un destructor Proporciona un entero unico para cada objeto Permite averiguar dinmicamente el a tipo de objeto Permite clonar un objeto Devuelve true si los objetos son la misma instancia Devuelve un string que representa al objeto actual

Tabla 4.1: Propiedades de las excepciones

4.2.

Doble aspecto de la herencia

Como ya se dijo en la denicin 2.3, la herencia es, a la vez, un mecanismo de especialio zacin y un mecanismo de implementacin. o o Esto es, una clase B puede heredar de otra clase A, por ser B una especializacin de A. Sin o embargo, puede ocurrir que el motivo por el cual B hereda de A sea la necesidad de construir una implementacin distinta (si se quiere, ms renada) de A. o a Ejemplo 4.2 La herencia entre clases que se observa en la gura 4.1, as como en las guras 4.2.a y 4.2.b sirve como mecanismo de especializacin. o Por otra parte, los ejemplos de las guras 4.2.c y 4.2.d muestran la herencia como mecanismo de implementacin. o

Figura 4.2: Herencia de especializacin y de implementacin o o

4.3.

Polimorsmo

Denicin 4.2 Podr o amos denir el polimorsmo como la capacidad que tiene una entidad para referenciar en tiempo de ejecucin a instancias de diferentes clases. o C# soporta el polimorsmo, lo cual quiere decir que sus entidades (las cuales poseen un unico tipo esttico y un conjunto de tipos dinmicos) pueden estar conectadas a una instancia a a de la clase asociada en su declaracin o de cualquiera de sus subclases. o Podr amos categorizar el polimorsmo en dos tipos: Paramtrico e Real y Aparente Sobrecarga Inclusin (basado en la herencia) o

4.3 Polimorsmo

27

Ejemplo 4.3 Dada la siguiente declaracin, siguiendo la jerarqu de clases de la gura 4.1, o a Poligono p; Triangulo t; Rectangulo r; Cuadrado c;

podemos decir que: te(p) = Poligono ctd(p) = {Poligono, Triangulo, Rectangulo, Cuadrado} te(t) = Triangulo ctd(t) = {Triangulo} te(r) = Rectangulo ctd(r) = {Rectangulo, Cuadrado} te(c) = Cuadrado ctd(c) = {Cuadrado} donde te signica tipo esttico y ctd signica conjunto de tipos dinmicos. a a Y por lo tanto las siguientes asignaciones ser vlidas: an a p = t; p = r; r = c; t = r; r = p; p = c; c = p; c = t;

Pero no lo ser an, por ejemplo:

4.3.1.

Sobrecarga

Denicin 4.3 La sobrecarga consiste en dar distintos signicados a un mismo mtodo u o e operador. C# soporta la sobrecarga de mtodos y de operadores. Uno de los ejemplos ms claros es e a el del operador +. Ejemplo 4.4 La expresin a + b puede signicar desde concatenacin, si a y b son de tipo o o string, hasta una suma entera, en punto otante o de nmeros complejos, todo ello depenu diendo del tipo de datos de a y b. Sin embargo, lo realmente interesante es poder redenir operadores cuyos operandos sean de tipos denidos por el usuario, y C# permite hacer esto. Pero conviene tener en cuenta que este tipo de actuacin slo es provechosa en aquellos o o casos en los que existe una notacin ampliamente usada que conforme con nuestra sobrecarga o (ms an, si cabe, en el caso de los operadores relacionales <, >, <= y >=). a u La tabla 4.2 muestra los operadores unarios que en C# se pueden sobrecargar, mientras que la tabla 4.3 hace lo propio con los operadores binarios. + ! ++ true f alse Tabla 4.2: Operadores unarios sobrecargables + / % & | << >> == ! = < > >= <= Tabla 4.3: Operadores binarios sobrecargables Cuando se sobrecarga un operador tal como +, su operador de asignacin asociado, o +=, tambin es sobrecargado impl e citamente. Ntese que el operador de asignacin no puede o o sobrecargarse y que los operadores sobrecargados mantienen la precedencia y asociatividad de los operandos. Tanto los operadores binarios como los unarios slo pueden ser sobrecargados mediante o mtodos estticos. e a

28

Tema 4. Herencia

Ejemplo 4.5 El cdigo 4.1 muestra un ejemplo de sobrecarga de operadores, tanto unarios, o como binarios. Obsrvese como en la l e nea 32 se vuelve a denir el operador *, previamente sobrecargado por el mtodo de la l e nea 29, pero con los parmetros en orden inverso. Esta prctica comn a a u evita que el operador sobrecargado tenga un orden prejado en sus operandos. El resultado mostrado por pantalla tras ejecutarse el mtodo Main() ser e a: Initial times day 00 time:00:00:59 day 01 time:23:59:59 One second later day 00 time:00:01:00 day 02 time 00:00:00
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

using System ; class MyClock { public MyClock () { } public MyClock ( unit i ) { Reset ( i ) ; } public void Reset ( unit i ) { totSecs = i ; secs = i % 60; mins = ( i / 60) % 60; hours = ( i / 3600) % 24; days = i / 86400; } public override string ToString () { Reset ( totSecs ) ; return String . Format (" day {0: D2 } time :{1: D2 }:{2: D2 }:{3: D2 }" , days , hours , mins , secs ) ; } public void Tick () { Reset (++ totSecs ) ; } public static MyClock operator ++( MyClock c ) { c . Tick () ; return c ; } public static MyClock operator +( MyClock c1 , MyClock c2 ) { return new MyClock ( c1 . totSecs + c2 . totSecs ) ; } public static MyClock operator *( uint m , MyClock c ) { return new MyClock ( m * c . totSecs ) ; } public static MyClock operator *( MyClock c , uint m ) { return ( m * c ) ; } private uint totSecs = 0 , secs = 0 , mins = 0 , hours = 0 , days = 0; }

4.3 Polimorsmo

29

37 38 39 40 41 42 43 44 45

class MyClockTest { public static void Main () { MyClock a = new MyClock (59) , b = new MyClock (172799) ; Console . WriteLine (" Initial times \ n " + a + \n + b ) ; ++ a ; ++ b ; Console . WriteLine (" One second later \ n " + a + \n + b ) ; } } Cdigo 4.1: Ejemplo de Sobrecarga de Operadores o

4.3.2.

Regla de aplicacin de propiedades o

Denicin 4.4 Un tipo T1 es compatible con otro tipo T2, si la clase de T1 es la misma o que la de T2 o una subclase de T2. Denicin 4.5 Regla de la Asignacin 1 o o Una asignacin x = y o una invocacin r(..,y,..) a una rutina r(..,T x,..), ser legal o o a si el tipo de y es compatible con el tipo de x. Denicin 4.6 Regla de Validez de un Mensaje 2 o Un mensaje ox.r(y), supuesta la declaracin X x, ser legal si: o a 1. X incluye una propiedad con nombre nal r. 2. Los argumentos son compatibles con los parmetros y coinciden en nmero. a u 3. Y r est disponible para la clase que incluye el mensaje. a

4.3.3.

Estructuras de datos polimrcas o

La lista doblemente enlazada implementada en el cdigo 2.7 es un claro ejemplo de eso tructura de datos polimorfa. Si en la l nea 23 de dicho cdigo en vez de poner private object data escribiramos o e private Figura data, siguiendo el ejemplo de jerarqu de clases de la gura 4.1, en un a instante dado podr amos tener una lista como la que se observa en la gura 4.3.

Figura 4.3: Ejemplo de estructura de datos polimorfa

4.3.4.

Operadores is y as

El operador is, cuya sintaxis es expresin is tipo, devuelve true si se puede hacer un o cast de la expresin expresin al tipo tipo. o o El operador as, con idntica sintaxis devuelve la expresin expresin convertida al tipo e o o tipo, o bien, si la conversin no est permitida, devuelve null. o a
1 2

En adelante, RA En adelante, RVM

30

Tema 4. Herencia

4.4.

Ligadura Dinmica a

Como ya dijimos en la denicin 4.1, si una clase B hereda de otra clase A, B puede o redenir mtodos de A e implementar mtodos que en A sean diferidos. e e Entonces cuando tengamos un objeto de la clase A y una invocacin a un mtodo redeo e nido en la clase B, la versin del mtodo que se ejecute depender del tipo dinmico del o e a a objeto de la clase A. En esto consiste la ligadura dinmica. a Ejemplo 4.6 En la gura 4.4 se muestra una jerarqu de clases en las que algunas de ellas a redenen el mtodo f de sus ancestras. Las letras griegas representan la versin de cada e o mtodo. e

Figura 4.4: Herencia y redenicin de mtodos o e Dadas las siguientes declaraciones: A oa; B ob = new B(); C oc = new C(); D od = new D();

A continuacin se muestra qu versin del mtodo f se ejecutar dependiendo del tipo o e o e a, dinmico del objeto oa: a oa = ob; oa.f oa = oc; oa.f oa = od; oa.f En C#, como en C++, la ligadura es esttica por defecto, siendo necesario incluir la a palabra clave virtual en aquellos mtodos que vayan a ser redenidos y a los cuales s se e aplicar ligadura dinmica. a a Aquellas subclases que quieran redenir un mtodo declarado como virtual en la clase e base debern emplear para ello la palabra clave override, como ya hemos visto en varios a ejemplos con el mtodo ToString(). e Ntese la diferencia entre un mtodo redenido y un mtodo sobrecargado. Los mtodos o e e e sobrecargados son seleccionados en tiempo de compilacin basndonos en sus prototipos o a (argumentos y valor de retorno) y pueden tener distintos valores de retorno. Un mtodo redenido, por contra, es seleccionado en tiempo de ejecucin basndonos en e o a el tipo dinmico del objeto receptor y no puede tener distinto valor de retorno del que tenga a el mtodo al que redene. e Ejemplo 4.7 El cdigo 4.2 muestra un ejemplo de redenicin de un mtodo heredado de la o o e clase base. Obsrvese el uso de la palabra clave virtual en la l e nea 4, as como de la palabra clave override en la l nea 9. Obsrvese tambin como el valor devuelto por el mtodo redenido e e e de la l nea 9 es el mismo que el del mtodo original de la l e nea 4, a saber, void. El resultado mostrado por pantalla tras ejecutarse el mtodo Main() ser e a: Dentro de la clase base Dentro de la clase derivada Dentro de la clase derivada

4.5 Clases Diferidas

31

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

using System ; class ClaseBase { public virtual void Status () { Console . WriteLine (" Dentro de la clase base ") ; } } class ClaseDerivada : ClaseBase { public override void Status () { Console . WriteLine (" Dentro de la clase derivada ") ; } } class L i g a d u r a D i n a m i c a T e s t { public static void Main () { ClaseBase b = new ClaseBase () ; ClaseDerivada d = new ClaseDerivada () ; b . Status () ; d . Status () ; b = d; b . Status () ; } } Cdigo 4.2: Redinicin de un mtodo heredado o o e

4.5.

Clases Diferidas

Denicin 4.7 Una clase diferida o abstracta es aquella que contiene mtodos abstractos, o e esto es, mtodos que deben ser implementados en las subclases. No se pueden crear instancias e de una clase abstracta. Para declarar en C# un mtodo como abstracto se emplea la palabra clave abstract, y e para implementarlo en alguna subclase utilizamos la palabra clave override. Si una clase hereda de otra clase abstracta y no implementa todos sus mtodos abstractos, e entonces sigue siendo abstracta. Ejemplo 4.8 El cdigo 4.3 muestra un ejemplo de una clase abstracta Figura, cuyo mtodo o e abstracto Area() es implementado en las subclases Rectangulo y Circulo, pero no en la subclase Triangulo. Es por ello que la subclase Triangulo sigue siendo abstracta. Para ser ms preciso, es a parcialmente abstracta (ver denicin 4.8). o Sin embargo el mtodo abstracto Perimetro() es implementado en las tres subclases. e
1 2 3 4 5 6

using System ; abstract class Figura { abstract public double Area () ; abstract public double Perimetro () ; }

32

Tema 4. Herencia

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

class Rectangulo : Figura { public Rectangulo ( double a , double b ) { altura = a ; base = b ; } public override double Area () { return ( base * altura ) ; } public override double Perimetro () { return (( base * 2) + ( altura * 2) ) ; } private double altura , base ; } class Circulo : Figura { public Circulo ( double r ) { radio = r ; } public override double Area () { return ( Math . PI * radio * radio ) ; } public override double Perimetro () { return ( Math . PI * radio * 2) ; } private double radio ; } abstract class Triangulo : Figura { public Triangulo ( double l1 , double l2 , double l3 ) { lado1 = l1 ; lado2 = l2 ; lado3 = l3 ; } public override double Perimetro () { return ( lado1 + lado2 + lado3 ) ; } private double lado1 , lado2 , lado3 ; } Cdigo 4.3: Clase abstracta Figura o Denicin 4.8 Una clase parcialmente abstracta es aquella que contiene mtodos abstractos o e y efectivos. Para referenciar al constructor de la clase base aadimos al nal del constructor de la n clase derivada lo siguiente: : base(argumentos). El constructor de la clase base es invocado antes de ejecutar el constructor de la clase derivada.

4.5.1.

Interfaces

Denicin 4.9 Una clase que unicamente contiene mtodos abstractos recibe el nombre de o e interface. Pero no confundamos, no es lo mismo que una clase abstracta, pues una clase abstracta puede estar parcialmente implementada. Adems una clase slo puede heredar de una unica clase abstracta, mientras que en C# a o est permitida la herencia mltiple de interfaces3 . a u Todos los mtodos de una interface, adems de ser abstractos como ya hemos dicho, deben e a ser pblicos. Por lo tanto las palabras clave abstract y public se pueden omitir. u Para declarar una interface se emplea la palabra clave interface; y para implementar una interface se emplea la notacin vista hasta ahora para la herencia. o Una interface puede heredar de otra interface; sin embargo, no puede contener miembros de datos, slo mtodos. o e
3

Lo veremos en profundidad ms adelante a

4.5 Clases Diferidas

33

Ejemplo 4.9 En el cdigo 4.4 se muestra un ejemplo de una interface IPersona, de la cual o heredan otras dos interfaces IEstudiante e IProfesor. Las tres son implementadas por la clase Ayudante. Obsrvese el convenio de nombrar a las interfaces con una I mayscula delante del e u nombre, a diferencia de las clases, que no la llevan. La gura 4.5 muestra el esquema de herencia e implementacin de las interfaces y la clase o en cuestin. o

Figura 4.5: Herencia e implementacin de interfaces o

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

interface IPersona { string Nombre { get ; set ; } string Telefono { get ; set ; } int Edad { get ; set ; } bool esMayorDeEdad () ; } interface IEstudiante : IPersona { double NotaMedia { get ; set ; } int A~ oMatricula { get ; set ; } n } interface IProfesor : IPersona { double Salario { get ; set ; } string Nss { get ; set ; } // N o seguridad social } class Ayudante : IPersona , IEstudiante , IProfesor { // M todos y propiedades requeridos por IPersona e public string Name { get { return name ; } set { name = value ; } } public string Telefono { get { return telefono ; } set { telefono = value ; } } public int Edad { get { return edad ; } set { edad = value ; } } public bool esMayorDeEdad () { return ( edad >= 18) ; } // M todos y propiedades requeridos por IEstudiante e public double NotaMedia { get { return notaMedia ; } set { notaMedia = value ; } } public int A~ oMatricula n { get { return a~ oMatricula ; } set { a~ oMatricula = value ; n n } }

34

Tema 4. Herencia

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

// M todos y propiedades requeridos por IProfesor e public double Salario { get { return salario ; } set { salario = value ; } } public string Nss { get { return nss ; } set { nss = value ; } } // Constructores para Ayudante public Ayudante ( string nom , string tlf , int ed , double nm , int am , double sal , string numSec ) { nombre = nom ; telefono = tlf ; edad = ed ; notaMedia = nm ; a~ oMatricula = am ; n salario = sal ; nss = numSec ; } // Otras implementaciones de constructores y m todos e ... public override ToString () { return String . Format (" Nombre : {0: -20} Tel fono : {1 ,9} Edad : {2 ,2}" + e "\ nSeguridad Social : {3} Salario : {4: C }" + "\ nNota media : {5} A~ o de matriculaci n : {6}" , n o nombre , telefono , edad , nss , salario , notaMedia , a~ oMatricula ) ; n } private private private private private private private } Cdigo 4.4: Herencia Mltiple mediante interfaces o u string nombre ; string telefono ; int edad ; double notaMedia ; int a~ oMatricula ; n double salario ; string nss ;

4.6.

Herencia, reutilizacin y extensibilidad del software o

A continuacin enumeramos cules son los requerimientos que debe cumplir un mdulo o a o para facilitar la reutilizacin: o 1. Variacin en tipos. Conseguida gracias a la genericidad. o 2. Variacin en estructuras de datos y algoritmos. Conseguida gracias a la ligadura dinmio a ca y el polimorsmo. 3. Independencia de la representacin. Conseguida gracias a la ligadura dinmica y el o a polimorsmo.

4.6 Herencia, reutilizacin y extensibilidad del software o

35

4. Captura de similitudes entre un un subgrupo de un conjunto de posibles implementaciones. Conseguida gracias a la herencia. 5. Agrupacin de rutinas relacionadas. Conseguida mediante la construccin de clases. o o Existen dos aspectos importantes en la reutilizacin de cdigo: por una parte, la creacin o o o de componentes reutilizables, y por otra parte, la utilizacin de dichos componentes. o En C# existe una gran coleccin (an en crecimiento) de elementos reutilizables. Noo u sotros trataremos ahora brevemente el contenido de System.Collections y la interface Collections.IEnumerable. La implementacin de la interface IEnumerate por parte de una clase contenedora dota o a sta de la posibilidad de emplear la instruccin foreach, cuya sintaxis es: e o foreach (Tipo nombreVariable in nombreArray) Mediante la instruccin foreach tenemos en cada iteracin en la variable nombreVariable o o el contenido de la clase contenedora. Obsrvese que este valor no puede ser modicado, slo e o puede consultarse. Para construir un iterador necesitamos alguna manera de avanzar el iterador, devolver el siguiente valor en la coleccin y comprobar en cada instante si ya hemos iterado sobre todos o los elementos de la coleccin. o Para ello la interface IEnumerable declara el mtodo IEnumerator GetEnumerator(). e No obstante, para realizar una implementacin concreta deben implementarse (valga la reo dundancia) los mtodos MoveNext() y Reset(), as como el mtodo de acceso Current, todos e e ellos de la interface IEnumerator. Ejemplo 4.10 El cdigo 4.5 muestra un ejemplo de una clase que implementa la interface o IEnumerable, de modo que se podr emplear la instruccin foreach con objetos de dicha a o clase (como puede observarse en la l nea ). Se trata de un array de 10 enteros cuyo iterador slo indexa los elementos que ocupan o posiciones impares (teniendo en cuenta que la primera posicin es la 0, la segunda la 1, ...). o El resultado mostrado por pantalla ser a: 1 3 5 7 9 11 13 15 17 19 Iterando... 3 7 11 15 19
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

using System ; using System . Collections ; class ArrayImpar : IEnumerable { public int [] a = new int [10]; public IEnumerator GetEnumerator () { return ( IEnumerator ) new ArrayImparEnumerator ( this ) ; } public int this [ int i ] { get { return a [ i ]; } set { a [ i ] = value ; } } private class A r r a y I m p a r E n umerator : IEnumerator { public A r r a y I m p a r E n u m e r ator ( ArrayImpar a )

36

Tema 4. Herencia

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

{ this . a = a ; indice = -1; } public void Reset () { indice = -1; } public bool MoveNext () { indice += 2; return ( indice <= 9) ; } publoc object Current { get { return a [ indice ]; } } private int indice ; private ArrayImpar a ; } class ArrayImparTest { public static void Main () { ArrayImpar ai = new ArrayImpar () ; for ( int i = 0; i < 10; i ++) { ai . a [ i ] = 2 * i + 1; Console . Write ( ai . a [ i ] + " ") ; } Console . WriteLine ("\ nIterando ...") ; foreach ( int elemento in ai ) Console . Write ( elemento + " ") ; } } Cdigo 4.5: Implementacin de un iterador o o Tratando ahora la cuestin referente a la ocultacin de informacin en los casos en los o o o que existe herencia diremos que en tales situaciones se viola el principio de caja negra, pues puede ocurrir que una subclase apoye algunos de sus mtodos en la implementacin concreta e o conocida de la clase base. Este es un factor negativo para la extensibilidad, pues si modicamos la clase base, todas sus subclases que hayan actuado de la manera anteriormente indicada se vern afectadas y a probablemente tambin debern modicar su implementacin. e a o Adems de los tres tipos de acceso vistos en la seccin 2.1.2 existe otro ms: internal. Una a o a propiedad con este modicador de acceso slo puede ser accedida desde cdigo perteneciente o o al mismo ensamblado en el que se haya denido dicha propiedad. La herencia privada, que est permitida en C++, no es soportada en C#. Sin embargo, a s se puede inhabilitar la herencia de una clase mediante la palabra clave sealed. Este tipo de clases, llamadas selladas, pueden ser tratadas de una forma ms eciente por parte del compia lador, ya que sus mtodos no pueden ser redenidos y por tanto se declaran automticamente e a como no virtuales.

4.7 Herencia m ltiple u

37

4.7.

Herencia m ltiple u

Denicin 4.10 Se dice que existe herencia mltiple de clases (tambin puede ser de intero u e faces) cuando una clase hereda directamente de ms de una clase. a Ejemplo 4.11 La gura 4.6.(a) muestra un ejemplo de herencia simple, mientras que la gura 4.6.(b) hace lo propio con la herencia mltiple. u

(a)

(b)

Figura 4.6: Herencia simple y mltiple u En C#, a diferencia de C++, no est permitida la herencia mltiple de clases. Sin ema u bargo, al igual que en Java, este hecho se solventa mediante la herencia mltiple de interfaces u y simple de clases. Ejemplo 4.12 En el cdigo 4.4 as como en la gura 4.5 se muestra un claro ejemplo de o herencia mltiple de interfaces. u

4.7.1.

Problemas: Colisin de nombres y herencia repetida o

Aunque la herencia mltiple nos ofrece varias ventajas a la hora de programar segn la u u metodolog OO, tambin implica algunos inconvenientes. a e A continuacin explicaremos dos de ellos: la colisin de nombres y la herencia repetida o o (aunque sta ultima, como veremos ms adelante, no se da en C#). e a La colisin de nombres tiene lugar cuando una clase hereda de dos o ms clases un o a mtodo con el mismo nombre y diferente implementacin. e o Ejemplo 4.13 En la gura 4.7 se muestra un ejemplo de colisin de nombres debida a la o herencia mltiple. u

Figura 4.7: Herencia mltiple y colisin de nombres u o

La herencia repetida se da cuando una misma propiedad es heredada por distintos caminos ms de una vez. a

38

Tema 4. Herencia

Figura 4.8: Herencia mltiple y herencia repetida u Ejemplo 4.14 En la gura 4.8 se muestra un ejemplo de herencia repetida debida a la herencia mltiple. u En C#, como ya hemos dicho, no hay herencia repetida, pero s puede darse colisin de o nombres en el caso en el que una interface hereda de dos o ms interfaces un mtodo con el a e mismo nombre. En este caso existen dos posibilidades: 1. Sobrecarga, si dieren en la signatura y/o en el valor de retorno. 2. Comparticin, si tienen la misma signatura y valor de retorno. o

4.7.2.

Ejemplos de utilidad

Ejemplo 4.15 En el cdigo 4.6 se muestra un ejemplo en el que una clase C hereda de dos o interfaces distintas A y B un mtodo con el mismo nombre f(object o), resultando en una e ambigedad de nombres. u
1 2 3 4 5 6 7 8 9 10 11 12

interface A { void f ( object o ) ; } interface B { void f ( object o ) ; } class C : A , B { // A . f () o B . f () ?? public void g () { f () ; } } Cdigo 4.6: Ambigedad de nombres debida a la herencia mltiple o u u Podemos resolver la potencial ambigedad de nombres dentro de la clase C incluyendo u declaraciones expl citas para cada instancia de interface heredada. Es ms, tambin podemos a e implementar un mtodo f() en C para el caso en el que se manipulen directamente objetos e de dicha clase. Estos cambios pueden observarse en el cdigo 4.7. o

1 2 3 4 5

class C : public public public }

A, B void void void

{ f ( string s ) { ... } A . f ( object o ) { ... } B . f ( object o ) { ... } Cdigo 4.7: Solucin a la ambigedad de nombres o o u

4.8 C#, Java y C++: Estudio comparativo

39

Ejemplo 4.16 Sea la jerarqu mostrada en la gura 4.9. Las letras enmarcadas representan a interfaces y las no enmarcadas, clases. En esta circunstancia podr amos pensar que se dar un caso de herencia repetida, pero a no es as .

Figura 4.9: Herencia mltiple sin herencia repetida (I) u La clase Z no necesita implementar los mtodos de la interface W, pues ya hereda dichas e implementaciones de la clase X. No obstante s deber implementar aquellos mtodos de la a e interface Y que no estn en la interface W. e Ejemplo 4.17 Sea ahora la jerarqu mostrada en la gura 4.10. Al igual que en el ejemplo a anterior, podr amos pensar que bajo estas premisas nos encontramos ante un caso de herencia mltiple. Pero, al igual que en el ejemplo anterior esto no es as u .

Figura 4.10: Herencia mltiple sin herencia repetida (II) u Si bien es cierto que la clase Z hereda los mtodos de la interface W por dos v no resulta e as, esto ser un problema, pues como ya vimos en el ejemplo 4.15, se puede solucionar fcilmente. a Otra solucin distinta a la expuesta en el ejemplo 4.15 pero igualmente vlida consiste en o a implementar una unica vez cada mtodo repetido. e

4.8.

C#, Java y C++: Estudio comparativo

Adems de las continuas referencias que durante todo el texto se han hecho hacia otros a lenguajes OO como Java y C++, a continuacin se muestran slo algunas comparaciones o o entre dichos lenguajes y C#. C# es muy parecido a Java. Normalmente el recolector de basura (garbage collector ) se encarga automticamente de los objetos que ya no son necesarios (por ejemplo, los no a

40

Tema 4. Herencia

referenciados por ninguna variable). Toda clase tiene como clase base de su jerarqu a a la clase object. En C# todo es un objeto. Los tipos primitivos tales como int pueden ser tratados como objetos. No es este el caso de Java donde los tipos primitivos son estrictamente tipos valor. C# permite paso por referencia en los tipos primitivos. C# incorpora la instruccin foreach junto con la interface IEnumerator, lo cual pero mite la construccin de un iterador. C# tiene verdaderos arrays multidimensionales. o C# ha retenido, aunque de una forma ms lgica y simple, la habilidad de C++ para a o sobrecargar operadores. En C# existe el concepto de propiedades, lo cual proporciona los mtodos de acceso get y set para consultar y modicar los valores de los miembros e de datos de una clase. Un programador de C# puede convertir rpidamente su cdigo a Java, pero no a la a o inversa. De hecho Java es conceptualmente un subconjunto de C#. C++ es muy complejo e inseguro. Ofrece demasiadas oportunidades al programador de manejar errneamente los punteros en aras de la eciencia. o C++ es dependiente del sistema. No est preparado para la Web. No maneja la memoria a como lo hacen C# o Java. El mero hecho de que el ncleo de C# est desprovisto del u e tipo puntero simplica enormemente su compresin por parte de un estudiante de POO. o

Indice de Figuras
2.1. 2.2. 2.3. 2.4. 2.5. 2.6. 2.7. Clientela y Herencia entre A y B . . . . . . . . . . . . Variables en los lenguajes tradicionales . . . . . . . . . Variables tipo puntero en los lenguajes tradicionales Variables en los lenguajes OO . . . . . . . . . . . . . . Ejemplo de copia supercial . . . . . . . . . . . . . . . Ejemplo de copia profunda . . . . . . . . . . . . . . . Ejemplo de variables idnticas . . . . . . . . . . . . . . e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 11 11 11 12 12 13 25 26 29 30 33 37 37 38 39 39

4.1. Jerarqu de clases . . . . . . . . . . . . . . . . . a 4.2. Herencia de especializacin y de implementacin o o 4.3. Ejemplo de estructura de datos polimorfa . . . . 4.4. Herencia y redenicin de mtodos . . . . . . . . o e 4.5. Herencia e implementacin de interfaces . . . . . o 4.6. Herencia simple y mltiple . . . . . . . . . . . . . u 4.7. Herencia mltiple y colisin de nombres . . . . . u o 4.8. Herencia mltiple y herencia repetida . . . . . . u 4.9. Herencia mltiple sin herencia repetida (I) . . . . u 4.10. Herencia mltiple sin herencia repetida (II) . . . u

41

42

INDICE DE FIGURAS

Indice de Tablas
2.1. 2.2. 2.3. 2.4. Tipos enteros primitivos . Tipos otantes primitivos Otros tipos primitivos . . Palabras reservadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 6 6 6 19 19 26 27 27

3.1. Algunas Excepciones estndar . . . . . . . . . . . . . . . . . . . . . . . . . . . a 3.2. Propiedades de las excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1. Propiedades de las excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2. Operadores unarios sobrecargables . . . . . . . . . . . . . . . . . . . . . . . 4.3. Operadores binarios sobrecargables . . . . . . . . . . . . . . . . . . . . . . .

43

44

INDICE DE TABLAS

Indice de Cdigos o
2.1. 2.2. 2.3. 2.4. 2.5. 2.6. 2.7. 3.1. 3.2. 3.3. 3.4. 3.5. 4.1. 4.2. 4.3. 4.4. 4.5. 4.6. 4.7. Clase Luna . . . . . . . . . . . . . . . . . . . . . . . . Ejemplo de Ocultacin de Informacin . . . . . . . . . o o Otro ejemplo de Ocultacin de Informacin . . . . . . o o Ejemplo de Clases Anidadas . . . . . . . . . . . . . . . Ejemplo de Constructores . . . . . . . . . . . . . . . . Ejemplo de implementacin del mtodo Clone() . . . o e Lista genrica doblemente enlazada . . . . . . . . . . . e Ejemplo del uso de asertos . . . . . . . . . . . . . . . . Ejemplo del uso de excepciones . . . . . . . . . . . . . Ejemplo del relanzamiento de excepciones . . . . . . . Uso de excepciones con ms informacin . . . . . . . . a o Ejemplo del uso de excepciones en vez de asertos . . . Ejemplo de Sobrecarga de Operadores . . . . . . . . . Redinicin de un mtodo heredado . . . . . . . . . . o e Clase abstracta Figura . . . . . . . . . . . . . . . . . . Herencia Mltiple mediante interfaces . . . . . . . . . u Implementacin de un iterador . . . . . . . . . . . . . o Ambigedad de nombres debida a la herencia mltiple u u Solucin a la ambigedad de nombres . . . . . . . . . o u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 7 8 9 12 13 14 18 18 20 21 22 28 31 31 33 35 38 38

45

46

INDICE DE CODIGOS

Bibliograf a
[Lip02] Stanley B. Lippman. C# Primer. A Practical Approach. Addison Wesley, 2002. [Mol04] J. Garc Molina. Apuntes de programacin orientada a objetos. 2004. a o [Poh03] Ira Pohl. C# by Dissection. Addison Wesley, University of California, 2003.

47

You might also like