Universidad Austral de Chile Facultad de Cs. de la Ingeniería Instituto de Informatica
Apuntes de Clases INFO 161 : Lenguajes de Programación Programación Orientada a Objetos
Prof. Luis Alberto Alvarez González Valdivia, Agosto de 1998.-
i
Tabla de Contenidos 1 INTRODUCCIÓN.
1
1.1
9
DISEÑO DIRIGIDO POR RESPONSABILIDADES
2 CLASES.
14
2.1 2.2 2.3 2.4 2.5 2.6
17 19 21 24 27 30
CREACIÓN DE OBJETOS DE UNA CLASE. FUNCIONES EN LÍNEA CONSTRUCTORES DESTRUCTORES. FUNCIONES AMIGAS EJERCICIOS.
3 MÁS CONCEPTOS SOBRE ORIENTACIÓN A OBJETOS
31
3.1 RELACIONES. 3.1.1 RELACIÓN “UN - TIPO - DE” (A - KIND - OF RELATIONSHIP) 3.1.2 RELACIÓN “ES UN(A)” ( IS - A RELATIONSHIP) 3.1.3 RELACIÓN “PARTE - DE” 3.1.4 RELACIÓN “TIENE - UN” 3.2 HERENCIA 3.3 HERENCIA MÚLTIPLE 3.3.1 CLASES ABSTRACTAS 3.3.2 EJERCICIOS
31 31 33 34 35 35 38 41 43
4 HERENCIA EN C++
46
4.1 4.2 4.3 4.4 4.5 4.6
47 48 49 50 50 53
TIPOS DE HERENCIA. CONSTRUCCIÓN DESTRUCCIÓN HERENCIA MÚLTIPLE. POLIMORFISMO CLASES ABSTRACTAS
5 SOBRECARGA DE OPERADORES
55
6 TIPOS GENÉRICOS
60
7 TIPOS GENÉRICOS (TÉMPLATE EN C++)
63
ii
LENGUAJES DE PROGRAMACIÓN
1 Introducción. Envío de Flores Si mando flores a una dama tengo las siguientes alternativas. Alternativas 1.Lo 1. Lo hago directamente enviándole un mensaje a Margarita la florista. 2.Usando 2. Usando otro objeto intermedio, por ejemplo Gertrudis, la secretaria. El objeto Margarita y el objeto Gertrudis tienen métodos que entienden el mensaje. El objeto Margarita tiene métodos que permiten realizar la acción. Si le pido a mi jefe Lalo que mande flores, probablemente no lo hará porque no tiene el método.
Orientación a Objetos
Página 1
LENGUAJES DE PROGRAMACIÓN
•
•
•
•
En POO, la acción se inicia mediante la transmisión de un mensaje (paso de mensajes) a un agente (objeto) responsable de la acción. El mensaje tiene codificada la petición y se acompaña de información adicional. Si el objeto receptor acepta el mensaje, significa que tiene los métodos para llevarla a cabo. El objeto receptor realiza la acción.
Si hubiese ido donde la florista Rosa el resultado habría sido el mismo, porque Margarita y Rosa pertenecen a la misma clase. Esta clase la podemos llamar Florista.
•
Todos los objetos de una misma clase tienen los mismos métodos.
Orientación a Objetos
Página 2
LENGUAJES DE PROGRAMACIÓN
Probablemente Margarita pedirá dinero y entregará una boleta, porque ese método los usan todos los comerciantes, o sea la clase florista pertenece a una clase mayor llamada comerciante y el objeto Margarita, conoce los métodos de la clase florista y todos los métodos de la clase comerciante Dicho de otra forma la clase florista hereda métodos de una clase jerárquicamente superior. Otros comerciantes son los panaderos, fotocopiadores, etc. Los comerciantes son humanos, como otro tipo de profesiones. Los Humanos son mamíferos, Los mamíferos son animales, Los animales son objetos materiales
Orientación a Objetos
Página 3
LENGUAJES DE PROGRAMACIÓN
Objeto Material Animal
Planta
Mamífero Perro
Humano
Comerciante
Pluto
•
• •
Flor Ornitorrinco
Ar Artista
Ingeniero
Florista
Fococopiador
Margarita
Rosa Pedro Pablo Ana
Orni
Clavel
Herencia.Las clases se pueden organizar en forma jerárquica por herencia. Una subclase heredará los métodos de una superclase. Una superclase abstracta se usa solo para crear subclases no posee objetos.
Orientación a Objetos
Página 4
LENGUAJES DE PROGRAMACIÓN
Un problema, los mamíferos dan a luz crías vivas. La ornitorrinco Orni es mamífero y pone huevos. Así que necesitamos método que codifiquen excepciones para anular métodos de las superclases.
•
Enlaces de Métodos. Un método se busca en la clase del objeto, si no se encuentra se busca en la superclase y así sucesivamente hasta que se encuentra. Una vez que se encuentra se ejecuta o de lo contrario emite un mensaje de error.
Volviendo al ejemplo. El hecho que yo no conozca con exactitud los métodos que usará Margarita, se conoce como ocultamiento de la información.
Orientación a Objetos
Página 5
LENGUAJES DE PROGRAMACIÓN
Resolver un problema complejo usando técnicas tradicionales, puede volverse muy engorroso, puesto que obliga a conocer variables, registros o parámetros que se usan anteriormente y de igual forma con el código que viene. Para resolver ese problema, se usan:
Procedimientos, Procedimientos y funciones permiten ocultar métodos, permite reutilización. Sin embargo la información la pueden ocultar sólo parcialmente. Por ejemplo, •
un procedimiento para manejar una pila.
•
Interfaz visible . rutinas, iniciar, sacar, meter y tope.
•
Se pude usar arreglo, punteros, listas enlazadas etc.
•
•
Los datos de la pila no pueden ser locales, deben ser compartidos, entonces deben ser globales. Supongamos un arreglo de nombre pila_de_datos.
Problemas. •
Todos los programadores deben saber este nombre para no crear otro igual.
Orientación a Objetos
Página 6
LENGUAJES DE PROGRAMACIÓN •
Los nombres iniciar, sacar, meter y tope son ahora reservados.
Módulos. La programación modular resuelve los problemas anteriores permitiendo dividir los módulos en dos partes, una parte privada y otra pública. La parte privada es sólo accesible por las rutinas al interior del módulo. Problemas. •
•
Que pasa si otros usuarios desean mantener más de una pila. La programación modular no permite hacer la instanciación de otros ejemplares.
Tipo de Datos Abstracto. •
•
•
Tipo definido por el programador. Conjunto de valores (podría ser infinito) y número de operaciones primitivas. Los usuarios pueden crear variables para el tipo definido.
Ejemplo, definir una pila como TDA y las operaciones iniciar, sacar, meter y tope, como las únicas operaciones válidas para pila. Orientación a Objetos
Página 7
LENGUAJES DE PROGRAMACIÓN
Los módulos se usan como implantación de TDA. El TDA es un concepto. Para construir un TDA se debe ser capaz de: 1.Exportar 1. Exportar una definición de tipo 2.Proporcionar 2. Proporcionar un conjunto de operaciones. 3.Proteger 3. Proteger los datos asociados, de tal manera que sólo se puedan usar con las operaciones establecidas. 4.Crear 4. Crear múltiples ejemplares del tipo. Los módulos están dirigidos hacia los puntos 2 y 3. Los objetos son tipos abstractos de datos.
Programación Orientada a Objetos (POO). La POO agrega ideas nuevas al concepto de TDA. Ellas son •
paso de mensajes. Cambio de enfoque entre hacerlo uno mismo invocando el método apropiado o que el objeto lo haga por uno.
•
Sobrecarga de nombres
•
Reutilización de software.
•
Mecanismos de herencia y polimorfismo (métodos que pueden ser aplicados a diferentes objetos)
Orientación a Objetos
Página 8
LENGUAJES DE PROGRAMACIÓN
1.1 Diseño Dirigido por Responsabilidades
¿ Que es POO ? Respuesta típica : clases, herencia, etc., sintaxis del lenguaje. Importante, delegación de responsabilidades. Esta técnica se llama diseño dirigido por responsabilidades responsabilidades. Una técnica útil es el uso de tarjetas CRC (Clases, Responsabilidad, Colaboradores), como se muestra en la figura Nombre de la Clase
Colaboradores
Responsabilidades
Algunas reglas •
•
•
Usar nombre pronunciables. Usar el subrayado _ (underline) para separar palabras dentro de un nombre o usar la primera letra mayúscula. Ejemplo “Ordenador_de_lista¨ u “OrdenadorDeLista” Usar adecuadamente las abreviaturas, por ejemplo “ordlist” no es un buen ejemplo, sin embargo “IDuser”
Orientación a Objetos
Página 9
LENGUAJES DE PROGRAMACIÓN
podría ser una abreviatura al número de identificación de usuario. •
•
No usar dígitos que confundan al lector por ejemplo 0 y O, 1 y l, 2 y Z, 5 y S, etc. Usar claramente variables boolianas, por ejemplo “Impresora_Lista” es mejor que “Estado_Impresora”.
Un ejemplo es el de cajeros automáticos
Lector_de_Tarjetas
Colaboradores
Muestre mensaje de bienvenida, espera tarjeta
Verificador_de_NIP
Pida Pida al Veri Verifi fica cado dor_ r_de de_N _NIP IP que que comp compru rueb ebee vali valide dezz
Sele Select ctor or_d _de_ e_Ac Actv tvid idad ad
Llame al Selector_de_Actvidad Devuelve tarjeta a usuario
Verificador_de_NIP
Colaboradores
Recibe nú número NI NIP de del Ma Manejador_de_cuenta. Devuelve falso si no hay cuenta
Manejador_de_cuenta
Presenta ventana de solicitud de NIP Recibe el NIP del usuario Compara NIP, devuelve resultado
Orientación a Objetos
Página 10
LENGUAJES DE PROGRAMACIÓN
Manejador_de_cuenta
Colaboradores
Verifica valides de cuenta; devuelve NIP Verifica información retiro/depósito
Selector_de_actividad
Colaboradores
Muestra menú de actividades
Manejador_de_depósito
Espera selección del usuario
Manejador_de_retiros
Llamar al manejador de la transacción adecuada
Manejador_de_Retiros
Colaboradores
Pregunta al usuario la cantidad a retirar
Manejador_de_cuenta
Verifiq Verifique ue la cantida cantidadd con Manejador Manejador_de _de_Cu _Cuent entaa
Distri Distribui buidor dor_de_ _de_efec efectiv tivoo
Diga al Distribuidor_de_efectivo que descargue efectivo
Caja_electrónica
Colaboradores
Dar efectivo
Manejador_de_retiros
Dar Dar sob sobre re de depós depósit itos os con con indi indica caci ción ón de hora hora
Manej Manejado ador_ r_de_ de_de depós pósit itos os
Recuperar sobre del depósito.
Orientación a Objetos
Página 11
LENGUAJES DE PROGRAMACIÓN
Ejemplos.Organización de escuela. profesores, alumnos, director, inspector, auxiliar, jardinero. Industria. Gerente, asesores, secretaria, Ingenieros, técnicos, trabajadores,
Orientación a Objetos
Página 12
LENGUAJES DE PROGRAMACIÓN
Orientación a Objetos
Página 13
LENGUAJES DE PROGRAMACIÓN
2 Clases. •
Un objeto es una instancia de una clase.
•
Un objeto tiene un estado y uno o varios métodos.
•
La estado es privado y puede ser accesado solo su propios métodos.
Objeto estado
métodos
Una clase, es a la cual pertenecen los objetos. Por lo tanto.
•
Una clase tiene una parte pública y una parte privada.
•
La parte privada tiene que ver con el estado del objeto.
•
La parte pública es la interfaz al objeto.
Orientación a Objetos
Página 14
LENGUAJES DE PROGRAMACIÓN
Ejemplo class Point { private : int xVal, yVal; public: void SetPt(int,int); SetPt(int,int); void OffsetPt(int,int); OffsetPt(int,int); };
Se declara una clase llamada Point. •
Tiene cuatro componente. xVal, yVal, SetPt y OffsetPt.
•
Tiene dos datos miembros y dos funciones miembros.
•
La parte privada está compuesta por los datos miembros.
•
•
La parte pública esta compuesta por las funciones miembros y la forma en como podrá accesarse los objetos. No importa el orden de la parte pública y privada.
Si la primera parte es la privada, se puede omitir private. Es decir quedaría. class Point { int xVal, yVal; public: void SetPt(int,int); void OffsetPt(int,int); void PrintPt() ; }; Orientación a Objetos
Página 15
LENGUAJES DE PROGRAMACIÓN
El encabezado de las declaraciones de las funciones miembros deben ser de la siguiente forma : tipo clase :: función (parámetros) por ejemplo void Point::SetPt(in Point::SetPt(int t x, int y) xVal=x; yVal=y; }
{
void Point::OffsetPt(int Point::OffsetPt(int x, int y) { xVal+=x; yVal+=y; } •
•
•
Esto se lee : “De la clase Point se declara setPt como ...” La función setPt asigna los valores privados xVal, yVal.
x e y a los valores
La función OffsetPt le agrega a xVal e yVal, los valores de x e y.
O sea
xVal+=x;
Orientación a Objetos
equivale a
xVal=xVal+x;
Página 16
LENGUAJES DE PROGRAMACIÓN
2.1 Creación de Objetos de una clase.
Se hace de la misma que la declaración de los tipos concretos, por ejemplo, Point punto_1, punto_2, xy, pt;
aquí, punto_1, clase Point .
punto_2, xy
y pt, son objetos de la
Point . punto_1
punto_2
xy
pt
Se pueden crear “infinitos” objetos de una clase. Se puede accesar un método público de un objeto, de la siguiente manera. objeto.método(parámetros);
Por ejemplo a un objeto lo podemos fijar en un punto pt.SetPt(10,10);
y posteriormente lo podemos incrementar en 2 unidades en x e y, o sea pt.OffsetPt(2,2);
Orientación a Objetos
Página 17
LENGUAJES DE PROGRAMACIÓN
Aquí estamos trabajando con el objeto pt. Intentar accesar un dato privado es ilegal, por ejemplo pt.xVal=10;
// ilegal
Otro ejemplo, Supongamos la clase fecha class fecha { int mes,dia,agno; public: void fijar(int,int,i fijar(int,int,int); nt); void siguiente(); void imprimir(); };
con las siguientes definiciones, void fecha::fijar(int d,int m, int a) { dia=d; mes=m; agno=a; } void fecha::siguiente() { dia++; if(dia>28).... } void fecha::imprimir() { cout<
Página 18
LENGUAJES DE PROGRAMACIÓN
}
Si definimos un objeto hoy, por ejemplo, fecha hoy;
Como poder obtener el dia, mes y agno del objeto hoy ? Respuesta. El dia, mes y agno de hoy son privados. Por lo tanto la única forma es a través de una función miembro. Tendremos entonces que agregar una función miembro a la clase. Llamemos a esta función obtener En la clase deberá definirse de la siguiente forma : void obtener(int*,in obtener(int*,int*,int*); t*,int*);
¿ Cual deberá ser su declaración.? Tarea: Hacer un programa que cree el objeto hoy de la clase fecha. Fije el objeto hoy en 25 de abril de 1996, a continuación incremente hoy al día siguiente y muestre el contenido sin usar el método imprimir y usándolo.
2.2 Funciones en línea
Cuando un método se declara en la misma definición de la clases se dice que esta “en línea”, del ejemplo
Orientación a Objetos
Página 19
LENGUAJES DE PROGRAMACIÓN
class fecha { int mes,dia,agno; public: void fijar(int d,int m, int a) {dia=d; mes=m; agno=a;} void siguiente(); void imprimir() {cout<
De esta forma se aumenta la eficiencia de los objetos de la clase. Otra forma de declarar las funciones en línea es usando la sentencia inline, de esta forma quedaría inline void fecha::fijar(int d,int m, int a) { dia=d; mes=m; agno=a; }
La declaración de un método dentro de la definición ayuda a la eficiencia, pero atenta contra la claridad del programa.
Conclusión. Usar funciones en línea sólo cuando la sea muy importante la eficiencia o cuando la definición sea realmente corta.
Orientación a Objetos
Página 20
LENGUAJES DE PROGRAMACIÓN
2.3 Constructores
Supongamos que declaramos un objeto pt de la clase Point y posteriormente, invocamos el métodos OffsetPt e imprimimos el resultado. ¿ Que ocurre ? Point pt; pt.OffsetPt(2,2); pt.PrintPt();
O creamos el objeto hoy de la clase fecha y a continuación invocamos el método siguiente() e imprimimos la nueva fecha. fecha hoy; hoy.siguiente(); hoy.imprimir();
Se debe entonces, declarar el objeto e inmediatamente despues inicializarlo, O sea, Point pt; pt.set(10,10);
y fecha hoy; hoy fijar(26,4,96) fijar(26,4,96)
Orientación a Objetos
Página 21
LENGUAJES DE PROGRAMACIÓN
Para que evitar cualquier olvido, el objeto debería poder inicializarse al momento de su declaración. Por ejemplo Point pt(10,10);
y fecha hoy(26,4,96);
¿ Como debería definirse la clase para que esto ocurra ? Si se declara un método público con el mismo nombre de la clase, entonces se puede realizar. El método con el mismo nombre de la clase y que tiene como objetivo inicializar los objetos que se declaren de la clase se llaman constructores. Así la clase quedaría class Point { int xVal, yVal; public: Point(int x, int y) {xVal=x; yVal=y;} void OffsetPt(int,in OffsetPt(int,int); t); void PrintPt() ; };
Notas : •
•
El constructor esta declarado en línea, pero no es necesario. El constructor no debe estar precedido por algún tipo o void.
Orientación a Objetos
Página 22
LENGUAJES DE PROGRAMACIÓN
De esta forma ahora podemos declarar, Point pt(10,10), pt1(0,0), pt2(1,3);
y fecha hoy(26,4,96), eclipse(5,5,96); eclipse(5,5,96);
Sería interesante poder usar la misma clase para crear objetos que permitan manejar puntos en coordenada polares u otras. De igual forma poder escribir las fechas de distinta manera. Para resolverlos se puede hacer uso de la “sobrecarga” y escribir varios constructores uno para cada caso. Por ejemplo class Point { int xVal, yVal; public: Point(int x, int y) {xVal=x; yVal=y;} Point() {xVal=yVal=0;} void OffsetPt(int,in OffsetPt(int,int); t); void PrintPt() ; }; Point::Point(float radio,float angulo) { Point::Point(float xVal=(int) (radio*cos(angulo)); (radio*cos(angulo)); yVal=(int) (radio*sin(angulo)); (radio*sin(angulo)); };
Orientación a Objetos
Página 23
LENGUAJES DE PROGRAMACIÓN
Note que como xVal e yVal son declarados enteros, es necesario que la operación sea convertida finalmente a enteros. Podemos crear los siguientes objetos Point pt(10,10), pt1(0.0,0.0), pt2;
Así •
pt trabaja
en coordenadas cartesianas,
•
pt1 en coordenadas polares y
•
pt2 en coordenadas cartesianas pero se inicializa con 0.
De igual manera con los objetos de la clase fecha. Se podría ingresar fecha de distintas maneras, por ejemplo en forma int dia,char* mes, int* agno.
2.4 Destructores.
En algunos casos los objetos creados, necesitan espacio en memoria adicional, el cual debe ser creado en la función constructor, por ejemplo crear un arreglo,
Orientación a Objetos
Página 24
LENGUAJES DE PROGRAMACIÓN
class vector { int tamagno; int* v; . public: vect ve ctor or(i (int nt); ); // co cons nstr truc ucto tor r . . }
donde vector::vector(int t) { vector::vector(int tamagno=t; v=new int[t]; // asigna espacio a // un arreglo de t // enteros }
Sin embargo, una vez que se deja de usar un objeto, se puede liberar la memoria que usar, para ello se usa un destructor. Los destructores tiene el mismo nombre de la clase pero están precedidos por un tilde (~)
Orientación a Objetos
Página 25
LENGUAJES DE PROGRAMACIÓN
ejemplo class vector { int tamagno; int* v; . public: vect ve ctor or(i (int nt); ); // co cons nstr truc ucto tor r ~vector(); // destructor . }
donde vector::~vector() { vector::~vector() delete [] v; // // // // }
Orientación a Objetos
libera el espacio que ocupaba el arreglo al que apunta v
Página 26
LENGUAJES DE PROGRAMACIÓN
2.5 Funciones Amigas
Supongamos las clases vector y matriz. El vector de 4 elementos y la matriz de 4 columnas o vectores. El acceso a cada uno de los elementos, se obtiene con la función elem().
Si se desea multiplicar, se puede construir una función que no pertenezca a ninguna de las clases y lo permita, esto sería, vector multiplicar(const matriz& m, const vector& v) vector r; for(int i=0;i<3;i++) { r.elem(i)=0; for(int j=0;j<3;j++) r.elem(i)+=m.elem(i,j)*v.elem(j); } return r; }
•
•
•
{
Desventajas, multiplicar() llama a elem() 4*(1+4*3). Si elem() verifica intervalo => aún mas tiempo. Si multiplicar fuera función única de la clase vector y la clase matriz, no habría necesidad de verificar y podría evitarse la función elem(). Pero, una función no puede ser miembro de dos clases. Recuerde, tipo clase::función(parámetros); clase::función(parámetros);
Orientación a Objetos
Página 27
LENGUAJES DE PROGRAMACIÓN
Solución. En la definición de clases debe existir forma de declarar una función que no pertenezca a la clases, pero que si tenga acceso a la parte privada de los objetos de la clase. Las funciones así declaradas, se llaman funciones amigas y se declaran de la siguiente forma class matriz; class vector { float v[4]; //.. friend vector multiplicar(const multiplicar(const matriz&, const vector&); } class matriz { vector v[4]; //.. friend vector multiplicar(const multiplicar(const matriz&, const vector&); }
Una función friend puede ser puesta tanto en la parte privada como en la pública.
Orientación a Objetos
Página 28
LENGUAJES DE PROGRAMACIÓN
Luego la función friend queda como sigue, vector multiplicar(const matriz& m, const vector& v) { vector r; for(int i=0;i<3;i++) { r.v[i]=0; for(int j=0;j<3;j++) r.v[i]+=m.v[i][j]*v.v[j]; } return r; } •
• •
Una función friend puede ser amiga de más de dos clases. Una función miembro, es además una interfaz a la clase. Una función miembro de una clase puede ser declarada amiga por otra, ejemplo,
class x { //.. void f(); }; class y { //.. friend void x::f(); };
ésto último se conoce como miembros amigos.
Orientación a Objetos
Página 29
LENGUAJES DE PROGRAMACIÓN
2.6 Ejercicios.
1.Escribir 1. Escribir programas completos con las clases Point y Fecha, sin usar constructores y usándolos. 3.Defina 3. Defina una clase letra que tenga como funciones: escribir_letra imprima las letras ‘a`,..,`z` y los dígitos ‘0’,..,’9’ escribir_ascii que imprima sus valores enteros, y escribir_hexa utilizando notación hexadecimal. •
• •
4.Cuales 4. Cuales son nombre apropiados para clases, objetos y métodos : Imprimir, raiz_cuadrada, complejo, año_bisiesto, fecha, hora. 5.5. - Escriba definiciones para las clases: complejo, vector, matriz. 6.6. - Escriba las declaraciones de todas las funciones miembros de las clases anteriores. Use Constructores. 7.7. - Escriba pequeños programas completos, donde se creen objetos de las clases anteriores y se pueda usar cada uno de los métodos o funciones miembros de los objetos.
Orientación a Objetos
Página 30
LENGUAJES DE PROGRAMACIÓN
3 Más Conceptos sobre Orientación a Objetos 3.1 Relaciones.
3.1.1 Relación “Un - Tipo - De” (A - Kind - Of Relationship) Consideremos que tenemos que escribir un programa para dibujar varios objetos tales como puntos, círculos, rectángulos, triángulos etc. Para cada objeto debemos tener una clase. Por ejemplo, si usamos un pseudo lenguaje para definir la clase punto, tenemos : class Punto { atributos: int x, y métodos: fijarX(int nuevoX) obtenerX() fijarY(int nuevoY) obtenerY() }
Orientación a Objetos
Página 31
LENGUAJES DE PROGRAMACIÓN
Si continuamos definiendo una clase para definir círculos tenemos, class Circulo { attributos: int x, y, radio métodos: fijarX(int nuevoX) obtenerX() fijarY(int nuevoY) obtenerY() fijarRadio(int nuevoRadio) obtenerRadio() }
Donde x e y define el centro de los objetos de circulo. Si comparamos ambas clases se observa lo siguiente: •
•
•
Ambas clases tienen los elementos x e y. En la clase Punto, estos describen la posición del punto, en la clase Circulo, estos describen el centro del circulo. Así x e y, tienen el mismo significado; en ambas clases describen, a través de un punto, la posición del objeto asociado. Ambas clases ofrecen el mismo conjunto de métodos para fijar y obtener x e y. La clase Circulo agrega un nuevo elemento llamado radio y los métodos de acceso correspondiente.
Orientación a Objetos
Página 32
LENGUAJES DE PROGRAMACIÓN
Conociendo las propiedades de la clase Punto, se puede describir un círculo como un punto + un radio y los métodos de acceso de este. De esta forma
un círculo es “ A - Kind - Of” punto . (un circulo es un tipo de punto) Sin embargo, un círculo es un poco más especializado. A - Kind - Of
Círculo
Un - Tipo - De
P un t o
La relación “A - Kind - Of” es usada a nivel de clases Para esta relación comúnmente se usa Las clases encerradas dentro de rectángulos. El nombre de la clase comienza con mayúscula El sentido de la flecha indica la relación “A - Kind Of”. • • •
3.1.2 Relación “Es Un(a)” ( Is - A relationship) Si creamos objetos de tales clases, su relación será “Es Un(a)” (Is - A). Ya que la clase Circulo es un tipo de Punto, un objeto de Circulo, digamos circulo es un punto. Consecuentemente, cada círculo se comporta como un punto. Por ejemplo, un punto se puede mover en la dirección Orientación a Objetos
Página 33
LENGUAJES DE PROGRAMACIÓN
x alterando el valor de x. De manera similar se puede mover
un círculo. Is - A
circulo
Es - Un
punto
Para representar la relación “Es - Un” se usará : • •
Los objetos se escribirán con letra minúscula. Los rectángulos tendran las esquinas redondeadas.
3.1.3 Relación “Parte - De” Algunas veces se necesita construir un objeto para combinarlo con otros. En la programación procedural se puede usar estructuras o records. Supongamos que se han creado varias clases para diferentes figuras, entre ella Circulo y Triangulo. Si decidimos crear una figura especial para representar nuestro logo, que consiste de un círculo y un triángulo. Así nuestro logo tendrá dos partes, círculo y triángulo que son “Parte - De” nuestro logo, es decir:
Orientación a Objetos
Página 34
LENGUAJES DE PROGRAMACIÓN
class Logo {
atributos : Circulo circulo Triangulo triangulo métodos: fijarLogo(Punto fijarLogo(Punto donde) }
Circulo Parte - De
Logo
Parte - De
Triangulo
3.1.4 Relación “Tiene - Un” Esta es la relación inversa de la relacion “Parte - De” Parte - De
Circulo
Tiene - Un
Parte - De
Logo
Tiene - Un
Triangulo
3.2 Herencia
Con la herencia podemos usar la relación “A - Kind - Of” para clases y la relación “Is - A” para objetos. Las clases que son “A - Kind - Of” otra clase comparte propiedades de las últimas. Por ejemplo si se declara la clase Circulo como “heredada de” Punto, se tiene: Orientación a Objetos
Página 35
LENGUAJES DE PROGRAMACIÓN
class Circulo heredada de Punto { atributos: int radio metodos: fijarRadio(int nuevoRadio) obtenerRadio() }
La clase Circulo hereda todos los atributos y métodos de la clase Punto, por lo tanto no necesita definir los atributos y métodos Punto. A nivel de objetos, un circulo, podría usar un punto, porque un circulo es un punto. Por ejemplo se puede definir un objeto circulo y fijar su centro se la siguiente forma : Circulo acirculo acirculo.fijarX(1) acirculo.fijarY(2) acirculo.fijarRadio(3)
// heredada de Punto // agregada a Circulo
La relación “Es un” implica que podemos usar un circulo en cualquier parte donde exista un punto. Por ejemplo si escribimos una función llamada mueve, que permite mover un punto en la dirección x mueve(Punto apunto, int delta_x) { apunto.fijaX(apunto.obtenerX apunto.fijaX(apunto.obtenerX()+delta_x) ()+delta_x) }
Orientación a Objetos
Página 36
LENGUAJES DE PROGRAMACIÓN
Un circulo heredado de punto puede usar un círculo como argumento, para mover el punto centro. Circulo acirculo ... move(acirculo,10)
// mueve el circulo // moviendo el punto centro.
Definiciones.Herencia.- Es el mecanismo con el cual una clase A hereda las propiedades de la clase B. Se dice “A es heredada de B”. Los objetos de la clase A tiene acceso a los atributos y métodos de la clase B sin necesidad de redefinirlos. Superclase/Subclase.- Si A es heredada de B, entonces B es llamada superclase de A y A es llamada subclase de B. Los objetos de una subclase comparten el mismo comportamiento que los objetos de la superclase. Las superclases también son conocidas como clases padres o clases base y las subclases como clases hijas o clases derivadas.
Orientación a Objetos
Página 37
LENGUAJES DE PROGRAMACIÓN
Del ejemplo Punto
heredada de
Circulo
3.3 Herencia Múltiple
Una clase puede ser subclase de mas de una superclase. Una subclase por lo tanto puede “mesclar” las propiedades heredadas de las superclases. Supongamos que existe una clase String que permite manipilación de texto. Por ejemplo con un método que permite agregar otro texto. Si en nuestro programa que dibuja objetos queremos agregar texto. Sería interesante que además podamos podamos mover el texto en el dibujo. Para resolver el problema crearemos una clase String_Dibujable que herede las propiedades de Punto y String. Orientación a Objetos
Página 38
LENGUAJES DE PROGRAMACIÓN
Punto
String
String_Dibujable
En el pseudo lenguaje usaremos coma (,) para separar las múltiples herencias. class String_Dibujable heredada de Punto, String { atributos: // todos los heredados de las // superclases métodos: // todos los heredados de las // superclases }
Podemos usar objetos de String_Dibujable como si fueran objetos Punto o String. Así
Orientación a Objetos
Página 39
LENGUAJES DE PROGRAMACIÓN
String_Dibujable dstring String_Dibujable ... move(dstring, 10) ...
Esto es posible porque dstring es un punto ( donde punto es un objeto de Punto) Por otro lado si en la clase String existe el método agregar para agregar texto, o sea también podemos hacer, dstring.agregar(“Esta dstring.agregar (“Esta caja es ...”)
Definición.Si la clase A hereda de mas de una clase, por ejemplo de B1, B2, ..., Bn, podemos hablar de múltiple herencia. Esto puede producir conflictos de nombre si al menos dos de las superclases definen propiedades con el mismo nombre. El problema de conflicto de nombre puede ser resuelto de la siguientes dos formas : 1.El 1. El orden en el cual las superclases son provistas. 2.La 2. La subclase puede resolver el conflicto especificando la superclase.
Orientación a Objetos
Página 40
LENGUAJES DE PROGRAMACIÓN
Otra forma es usando otra superclase para las clases que heredan. A
B
C
D
Las múltiples herencias son un mecanismo poderoso, sin embargo puede producir conflictos de nombres.
3.3.1 Clases Abstractas Con herencia forzamos a una subclase a tener las mismas propiedades que la superclase. Consecuentemente, los objetos de una subclase tienen el mismo comportamiento que los objetos de la superclase. Orientación a Objetos
Página 41
LENGUAJES DE PROGRAMACIÓN
En el programa de dibujo, cada objeto deberá proveer un método para dibujar su área. Sin embargo, dibujar un círculo es diferente a dibujar un rectángulo. Supongamos el método print(). que fuerce a todos los objetos dibujables a tener tal método. Para esto definamos la clase Objeto_Dibujable de la cual todos los objetos dibujables heredan sus propiedades : abstracta class Objeto_Dibujable { atributos: métodos: print() }
Se introduce la palabra clave abstracta, para especificar que las heredadas deben re definir el método print(). Así, desde el punto de vista de una clase abstarcta las propiedades estas especificadas, pero no definidas.
Orientación a Objetos
Página 42
LENGUAJES DE PROGRAMACIÓN
Ejemplo class Punto heredada de Objeto_Dibujable Objeto_Dibujable { atributos: int x,y métodos : fijarX(int nuevoX) obtenerX() fijarY(int nuevoY) obtenerY() print() //re definida para Punto }
Definición. Una clase A es llamada abstracta si sólo es usada como superclase para otras clases. La clase A sólo especifica propiedades. Esta no es usada para crear objetos. Las clases derivadas deben definir las propiedades de A.
3.3.2 Ejercicios 1.- Herencia. Considere los siguientes programas de dibujo. a) Defina la clase Rectángulo por herencia de Punto. El punto debe indicar la esquina superior izquierda del rectángulo. ¿ Cuales son sus atributos. ?. ¿ Que métodos adicionales debe agregar ?.
Orientación a Objetos
Página 43
LENGUAJES DE PROGRAMACIÓN
b) Todos los ejemplos anteriores estan basados en dos dimensiones. Si ahora introduce objetos en tres dimensiones como esferas y cubos. Diseñe una clase Esfera que use la Clase Punto3D. Especifique el rol del punto en una esfera. ¿ Que relación existe entre la clase Punto y Punto3D ? c) Que funcionalidad le da mover() a los objetos 3D ?. Puede usarse. d) Dibuje un grafo de herencia que incluya las clases Objeto_Dibujable, Punto, Círculo, Rectángulo, Punto3D y Esfera.
e) Fijece en el gráfo de la clase Esfera. . ¿ Puede la siguiente ser una definición ?
Punto
Circulo
Esfera
Orientación a Objetos
Página 44
LENGUAJES DE PROGRAMACIÓN
class Esfera heredada de Circulo { atributos: in t z // agrega tercera dimensión
métodos: fijarZ(int nuevoZ) obtenerZ() }
De razones para ventajas y desventajas de esta alternativa. 2.- Herencia Múltiple. Compare el gráfo de la figura con el de clase. ¿Cuales son las diferencias ?. Que conflictos de nombres ocurren ? A
A
B
C
D
Orientación a Objetos
Página 45
LENGUAJES DE PROGRAMACIÓN
4 Herencia en C++ Asumamos que tenemos la clase Punto como, class Punto { int _x, _y; public: Punt Pu nto( o() ) {_ {_x= x=_y _y=0 =0;} ;} Punto(const int x, const int y) {_x=x; _y=y;} ~Punto() {// nada } void fijarX(const int x){_x=x;} void fijarY(const int y){_y=y;} int obtenerX(){return _x;} int obtenerY(){return _y;} }
La palabra usada anteriormente como “heredada de” se reemplaza por dos puntos (:). Si la clase Punto3D se hereda de la clase Punto se escribe,
Orientación a Objetos
Página 46
LENGUAJES DE PROGRAMACIÓN
class Punto3D : public Punto { int _z; public: Punto3D(){fijarX(0);fijarY(0);_z=0} Punto3D(const int x, const int y, const int z,) { fijarX(x);fijarY(y);_z=z } ~Punto3D() {// nada } void fijarZ(const int z){_y=z;} int obtenerZ(){return _z;} }
4.1 Tipos de Herencia.
En C++ existen dos tipos de herencia : Pública Privada Si se usa herencia pública: Todos lo que es declarado privado en la superclase, permanece privado. Todos lo que es declarado público en la superclase, permanece público. Si se usa herencia privada : Todo lo declarado en la superclase (público y privado), es privado en la subclase.
Orientación a Objetos
Página 47
LENGUAJES DE PROGRAMACIÓN
4.2 Construcción
Note que la inicialización de una instancia de Punto3D se hace usando un constructor, el cual llama los métodos públicos de Punto para inicializar x e y. Sin embargo, podría haberse usado el constructor de Punto, es decir, class Punto3D : public Punto { int _z; public: Punto3D():Punto(){_z=0;} Punto3D(const int x, const int y, const int z,): Punto(x,y) {_z=z; } ~Punto3D() {// nada } void fijarZ(const int z){_y=z;} int obtenerZ(){return _z;} }
Si se usan mas superclases, los constructores se separan por comas. Supongamos que la clase Logo esta formada sólo por un objeto de la clase Circulo y otro de la clase Rectangulo, entonces, quedaría
Orientación a Objetos
Página 48
LENGUAJES DE PROGRAMACIÓN
class Logo { Circulo acirc; Rectangulo arec; ... public: Logo(Circulo c, Rectangulo r): Circulo(a),Rectangulo(r) {} .... }
De acuerdo a esto la clase
Punto
pudo haber sido escrita
class Punto { int _x, _y; public: Punto():_x(0),_y(0) {} Punto(const int x, const int y): _x(x),_y(y){} ... ... }
4.3 Destrucción
Si un objeto es destruido, los destructores de las superclases también son invocados.
Orientación a Objetos
Página 49
LENGUAJES DE PROGRAMACIÓN
4.4 Herencia Múltiple.
Las superclases se separan por comas, ejemplo class StringDibujable: public Punto, public ObjetoDibujable { ... public: StringDibujable(...):Punto(...), ObjetoDibujable(...) { ... } };
4.5 Polimorfismo
Es posible crear métodos virtuales de alguna clase particular, para poder mas tarde se definidos. En C++ class ObjetoDibujable ObjetoDibujable { public: virtual void print(); };
Si ahora declaramos class Punto : public ObjetoDibujable { ... public: void print(){ ... // definición } }
Orientación a Objetos
Página 50
LENGUAJES DE PROGRAMACIÓN
De nuevo print() es un método virtual, porque hereda esta propiedad de ObjetoDibujable. Si se crea una función cualquiera, encargada de dibujar un ObjetoDibujable cualesquiera, puede ser definida como : void desplegar(const ObjetoDibujable ObjetoDibujable &obj) { // instrucciones necesarias previas obj.print(); }
Cuando se usa métodos virtuales, algunos compiladores reclaman, si el destructor de la correspondiente clase no es declarado también virtual. Esto es necesario cuando se usan punteros a una subclase (virtual) y se desea destruir objetos de estos últimos. Si el destructor es virtual, se invoca al destructor del objeto actual referenciado ( y así, recursivamente a todos los destructores de las superclases). Ejemplo
Orientación a Objetos
Página 51
LENGUAJES DE PROGRAMACIÓN
class Color { public: virtual ~Color(); }; class Rojo: public Color { public: ~Rojo(); //virtualmente heredada }
de Color
class RojoFuerte: public Rojo { public: ~RojoFuerte(); };
Si se define paleta como, Color *paleta[3]; paleta paleta[0] [0]=ne =new w Rojo; Rojo; //dinámicamente paleta[1]=new RojoFuerte; paleta[2]=new Color;
crea un nuevo Rojo
El operador new crea un nuevo objeto del tipo especificado en memoria dinámica y retorna un puntero de éste. Así, new Rojo retorna un puntero a un objeto de la clase Rojo y lo asigna al primer elemento del arreglo paleta. Los elementos de paleta son punteros a Color y porque Rojo es-un Color la asignación es válida. El operador contrario es delete, que explícitamente destruye un objeto referenciado por un puntero, de esta forma se puede usar Orientación a Objetos
Página 52
LENGUAJES DE PROGRAMACIÓN
delete palette[0]; // invoca al destructor ~Rojo y de ~Color() delete palette[1]; // invoca a destructor ~RojoFuerte y ~Color() delete palette[2]; // invoca al destructor ~Color()
La invocación a varios destructores es debido a que los destructores son virtuales. Si los destructores no hubiesen sido declarados como virtuales sólo se habría invocado el destructor ~Color.
4.6 Clases Abstractas
Las clases abstractas son definidas como clases ordinarias. Sin embargo, algunos de sus métodos pueden ser diseñados para que necesariamente deban ser definidos en las subclases. Llamaremos signature o firma al tipo que retorna, nombre y parámetros que usa, pero no a la definición. Ejemplo, class ObjetoDibujable ObjetoDibujable { public: ... virtual void print()=0; Orientación a Objetos
Página 53
LENGUAJES DE PROGRAMACIÓN
};
Con “=0” estamos obligando a el método print() sea definido en la subclase. También a este tipo de métodos se les denomina métodos puros. La clases abstractas contienen sólo métodos puros.
Orientación a Objetos
Página 54
LENGUAJES DE PROGRAMACIÓN
5 Sobrecarga de Operadores Para tipos definidos por el usuario, es posible re-definir los operadores establecidos para los tipos concretos, es decir +, -, * , / , etc. Por ejemplo supongamos la clase Complejo de la siguiente forma class Complejo { double _real, _imag; public: Complejo(): _real(0.0), _imag(0.0) {} Complejo(const double real, const double imag) : _real(real), _imag(imag) {} Complejo suma(const Complejo op); Complejo mul(const Complejo op); ... };
Luego si se define Complejo a(1.0, 2.0), b(3.5, 1.2), c; c=a.suma(b);
se asigna la suma de a y b a c. Esto es correcto, sin embargo resulta mas entendible usar el operador +.
Orientación a Objetos
Página 55
LENGUAJES DE PROGRAMACIÓN
Afortunadamente C++ permite la sobre carga de operadores. De esta forma, usando sobrecarga de operadores se escribe : class Complejo { ....; public: ... Complejo operator+(const Complejo &op) { double real = _real+op._real, imag = _imag+op._imag; _imag+op._imag; return(Complejo(real,imag)); } ... };
Ahora podemos escribir la expresión anterior como : c = a + b;
esto es interpretado como, c = a.operator+(b); a.operator+(b);
si queremos usar la función de la siguiente forma : c = operator+(a,b); operator+(a,b);
se comete un error porque la sobrecarga del operador no esta definida con dos argumentos : Orientación a Objetos
Página 56
LENGUAJES DE PROGRAMACIÓN
Por otra parte se dice que por definición a+b es equivalente a operator+(a,b), por lo tanto se debe definir como, Complejo operator+(Complejo a1, Complejo a2) { return complejo(a1._real + a2._real, a1._imag+a2._imag) }
sin embargo, es necesario accesar la parte real y imaginaria de un Complejo, por lo tanto una buena definición sería, class Complejo { double _real, _imag; public: double real(return _real); double imag(return _imag); ... ... }; Complejo operator+(Complejo a1, Complejo a2) { return complejo(a1.real + a2.real, a1.imag+a2.imag) }
Las funciones amigas permiten accesar la parte privada, entonces podría resultar mejor declarar las clase y sus operadores como sigue,
Orientación a Objetos
Página 57
LENGUAJES DE PROGRAMACIÓN class Complejo { double _real, _imag; public: ... friend Complejo operator+(Complejo a1, Complejo a2); ... ... }; Complejo :: friend Complejo operator+(Complejo a1, Complejo a2) { return complejo(a1.real + a2.real, a1.imag+a2.imag) } ... ...
Orientación a Objetos
Página 58
LENGUAJES DE PROGRAMACIÓN
La clase completa quedaría, class Complejo { double _real, _imag; public: Complejo(double r=0, double i=0) {_real=r; _imag=i; } void print(); friend Complejo operator+(Complejo,Complejo); friend Complejo operator*(Complejo,Complejo); friend Complejo operator/(Complejo,Complejo); }; void Complejo :: print(){ cout << _real << “ + “<<_imag <<‘\n’; } Complejo operator+(Complejo a1, Complejo a2) { return complejo (a1._real + a2._real, a1._imag+a2._imag) } Complejo operator*(Complejo a1, Complejo a2) { return complejo(a1._real*a2._real a1._imag*a2._imag, a1._real*a2._imag + a1._imag*a2._real) }
Tarea Complejo operator/(Complejo a1, Complejo a2)
Orientación a Objetos
Página 59
LENGUAJES DE PROGRAMACIÓN
6 Tipos Genéricos Los Tipos de Datos Abstractos (TDA) se usan para definir tipos creados por el usuario. A partir de los cuales nacen las clases. Por ejemplo se puede pensar en una lista de manzanas, autos o cualquier lista. La definición semántica de la lista es siempre la misma. Solo cambia el tipo de datos de acuerdo al tipo de lista. Esta información adicional puede ser especificada por un parámetro genérico el cual es especificado al momento de la creación de la instancia.. De esta forma una instancia de un TDA genérico es una instancia de una variante particular de un TDA. Por ejemplo Lista Lista_de_Manzanas Lista_de_Manzanas
Los paréntesis en ángulos encierran el tipo de dato variante del TDA Lista. Lista_de_Manzanas tiene las mismas interfaces de cualquier lista pero funciona con instancias de tipo Manzanas.
Orientación a Objetos
Página 60
LENGUAJES DE PROGRAMACIÓN
Cuando se define una clase, debemos especificar que estamos definiendo un tipo genérico. Sin embargo no se sabe que tipo de clase se usará. O sea, se debe definir una clase con un “recipiente” donde se indique el tipo de clase. La definición de clase debe proveer un “molde” ( template). La clase, de acuerdo a nuestra definición esta definida para un tipo particular de objetos. Un ejemplo para la definición para un tipo genérico será: template class Lista T { atributos : ... //Datos //Datos necesario necesarios s métodos : agregar (T elemento) T obtener_primero obtener_primero() () T obtener_proximo obtener_proximo() () ... }
La clase anterior es como cualquier clase. Sin embargo la clase lista es declarada como un “molde” para varios tipos de listas. El identificador T es el “ recipiente”. Por ejemplo para una lista de manzanas.
Orientación a Objetos
Página 61
LENGUAJES DE PROGRAMACIÓN
Lista Lista_de_Manzan Lista_de_Manzanas as Manzanas una_manzana, otra_manzana Manzanas.agregar(otra_manzana) Manzanas.agregar(una_manzana)
La primera línea declara Lista_de_Manzanas como una lista de Manzanas. La definición anterior es similar a: class Lista { atributos : ... //Datos //Datos necesario necesarios s métodos : agregar (Manzana elemento) Manzana obtener_primero() obtener_primero() Manzana obtener_proximo() obtener_proximo() ... } (Debe haber una definición de manzanas)
El compilador debe poder crear diferentes listas es decir: Lista Lista_de_Manzanas Lista_de_Manzanas Lista Lista_de_Autos
Podemos adicionalmente declarar mas listas de manzanas, es decir, Lista una_Lista Lista otra_Lista
Orientación a Objetos
Página 62
LENGUAJES DE PROGRAMACIÓN
Definición.- (Clase template o molde ) Si una clase A es parametrizada con un tipo de datos B . A es llamada una clase molde o clase template. Una vez que se crea un objeto de A, B reemplaza al tipo de datos. Esto permite la definición de una clase basada en un molde específico para A y el tipo de datos que se indica.
7 Tipos Genéricos (Témplate en C++) Los tipos de datos genérico en C++ se denominan clases templates y son similares a las clases normales. Ejemplo template class Lista : ... { public: ... void agregar(const T dato); ... };
Orientación a Objetos
Página 63
LENGUAJES DE PROGRAMACIÓN
De acuerdo a esto debemos especificar el tipo de lista que deseamos construir, Lista lista-enteros;
automáticamente, el compilador interpreta el método agregar como, void agregar(const int dato);
También pueden ser definidas funciones template, por ejemplo, template void swap (T &a, T &b) { T tmp=a; a=b; b=tmp; };
y un posible programa sería
Orientación a Objetos
Página 64
LENGUAJES DE PROGRAMACIÓN
int main() { int a=3; b=16; double p1=3.14; e=2.17; Persona yo (“Luis Alvarez”) tu (“Juan Peres”) swap(a,b); cout <<“ a = “ << a << “ b = “ << b; swap(p1,e); cout <<“ pi = “ << pi << “ e = “ << e; swap(yo,tu); cout <<“ yo = “ << yo << “ tu = “ << tu; return(0); }
template void swap (T &a, T &b) { T tmp=a; a=b; b=tmp; }
El template puede tener mas de un argumento, Orientación a Objetos
Página 65
LENGUAJES DE PROGRAMACIÓN
ejemplo, template
class Diccionario
{
... public : ... K sacar_1(const T palabra_2); T sacar_2(const K
palabra_1);
... }
Template también puede ser usado para crear clases parametrizadas, ejemplo. template class Stack { T _almacen[tamaño]; _almacen[tamaño]; public : ... }; Stack mi_stack;
Orientación a Objetos
Página 66
LENGUAJES DE PROGRAMACIÓN
Propiedades de listas simplemente enlazadas . 1. Elemento Elemento actual. Un iterador visita el elemento en uso. 2. Función sucesor . El iterador regresar el próximo elemento a ser visitado. 3. Condición de término. El iterador debe proveer una condición de término, no necesita chequear que todos los elementos hayan sido visitados. l
• • •
l
l
l
Primer nodo o nodo cabeza. No tiene predecesor. Nodo del medio. Tiene predecesor y sucesor. Último nodo o cola. No tiene sucesor.
Una lista solo tiene nodos. No es posible devolverse ni comenzar en la mitad de la lista. ¿ Cuales son la operaciones ofrecidas por una lista ? La lista tiene dos elementos bien conocidos que son la cabeza y cola.
Orientación a Objetos
Página 67
LENGUAJES DE PROGRAMACIÓN
Un nuevo nodo puede ser colocado en la lista como: El puntero es fijado en la cabeza, en nuevo nodos es la nueva cabeza,
• •
En forma similar, un nodo puede ser facilmente agregado a la cola como: El puntero a la cola es fijado en el nuevo nodo, el nuevo nodo pasa a ser la cola. • •
La funcion inversa en sacar (o borrar) el nodo sucesor pasa a ser la nueva cabeza, la antigua cabeza se descarta.
• •
Tres primitivas permiten hacer lo anterior y son: saca-primero : retorna el datos del nodo cabeza, saca-último esta-vacía
: retorna el dato del nodo cola, : retorna verdadero o falso.
Orientación a Objetos
Página 68
LENGUAJES DE PROGRAMACIÓN
Implantación.El block básico de una lista es el nodo. Así la primera clase a declarar será Nodo. Lo único que contiene un nodo is un puntero al próximo vecino (a la derecha). Class Nodo { Nodo *_derecha; public : Nodo(Nodo *derecha=NULL) : _derecha(derecha) _derecha(derecha) {} Nodo(const Nodo &val) : _derecha(val._derecha) _derecha(val._ derecha) {} const Node *derecha() const { return _derecha } Nodo *&derecha(){ return _derecha } Nodo &operador =(const Nodo &val) { _derecha=val._derecha; return *this; } const int operator == (const Nodo &val) const {return _derecha==val._derecha;} const int operator != (const Nodo &val) const {ret {r etur urn n !( !(*t *thi his= s==v =val al); ); } };
La palabra const justo antes del cuerpo del método, declara a éste como constante en relación a los elementos del Orientación a Objetos
Página 69
LENGUAJES DE PROGRAMACIÓN
objeto invocado. Consecuentemente, sólo se permite usar este mecanismo en declaración o definición respectivamente. El modificador const también es usado para chequear sobrecarga. De esta forma, class
Xxx {
... int xx() const; int xx() ; };
declara dos métodos diferentes. El primero es usado en contextos constantes, mientras que el segundo en contextos variables. La clase Nodo implementa un nodo simple donde : Constructores. Permiten la definición de objetos inicializados a partir de otros ya existentes. operator =. Cada objetos debe saber como asignar otros objetos (del mismo tipo) a si mismo. operador ==. Cada objeto deberá saber como compararse con otro objetos. operador != . Se aplica usando en operador == y el puntero this. •
•
•
Orientación a Objetos
Página 70
LENGUAJES DE PROGRAMACIÓN
De esta forma podemos usar Node a,b; ... if (a!=b)...
note que se usa el mismo operator
==
de la clase.
Todos los nodos deben contener datos. Los datos pueden ser de cualquier tipo, para lo cual usaremos una clase template. template class Data_Nodo : public Nodo { T _data; public: Data_Nodo(const T data, Data_Nodo *derecha=NULL) : Nodo(derecha), _data(data) {} Data_Nodo(const Data_Nodo &val) : Nodo(val), _data(val._data) {} const Data_Nodo *derecha() const { return((Data_Nodo *) Nodo::derecha());} ... ...
Orientación a Objetos
Página 71