Tres elementos esenciales de la programación orientada a objetos Abstracción Herencia Polimorfismo Objetos Modelado en objetos importancia del diagrama de clases: – es el diagrama esencial para UML – es el depositorio central de la información acerca del sistema – refleja el mundo real y la visión que se tiene acerca de él – es menos dependiente de detalles que el MDF y que los diagramas dinámicos – posee estabilidad con la evolución – organiza el mundo real en elementos manejables casos de uso en el modelado en objetos Objetos Dr. Dr.Deni DeniTorres TorresRomán: Román: 1 Tareas para el modelado en objetos recopilación de información: casos de uso definir diagrama de contexto: actores-sistema identificar candidatos a objetos: sustantivos en los casos de uso seleccionar clases:eliminar redundancia, vaguedad, irrelevancia; atributos, operaciones, roles; eventos; lo no perteneciente al mundo real crear diagrama de clases identificar relaciones: agregación, dependencia, herencia, asociación reflexiva determinar atributos y operaciones refinar el modelo para herencia: jerarquía probar el modelo: casos de uso, diccionario del modelo Empaquetamiento sistemas grandes necesitan ser particionados para lograr visibilidad y manejar la complejidad agrupamiento de objetos ayuda a crear diferentes niveles de abstracción un sistema es una colección de paquetes un paquete es un agrupamiento lógico de elementos del modelo ( clases , casos de uso,procesadores,...) con alta cohesión y bajo acoplamiento un paquete puede ser descompuesto en otros un paquete puede ser visto como un subsistema o un módulo Ejemplos: Objetos 2 Operador de referencia & una referencia es un alias necesita, a diferencia de un puntero, ser siempre inicializada una referencia contiene una dirección pero se comporta como un valor Ejemplo – – – – – – int valor = 50; int &refValor = valor; int &refValor2; refValor +=5; int otroValor = refValor; int *ptr = &refValor; //declaración de la referencia //ERROR en “ “ “ //valor = 55 // otroValor = 55 // incializa al puntero // con la dirección de valor Objetos Llamadas por valor, puntero y referencia void Cambio (int a, int b) { int local = a; a = b; b = local; } void Cambio (int *pa, int *pb) { int local = *pa; *pa = *pb; *pb = local; } //Cambio (x, y); //Cambio (&x, &y); void Cambio (int &a, int &b) { int local = a; a = b; b = local; } //Cambio (x, y); 3 Operador de resolución de ámbito :: Ejemplo #include <iostream.h> int a; void main() { float a = 1.5; ::a = 5; cout<<“local a”<< a <<endl; cout<<“global a”<< ::a <<endl; } ::variable permite el acceso a un elemento oculto en el ámbito actual Objetos Estructura específica de los datos de una clase class NombreDeLaClase { private: int datoInt; char* chPtr; protected: object* objectPtr; public: struct nombreStructure; }; características de cada tipo de dato Objetos 4 Estructura específica de las funciones miembros de una clase ret NombreDeLaClase::NombreDelMetodo { cuerpo //código } las funciones miembros o métodos pueden ser también private, protected y public las funciones miembros pueden ser: modificadoras, selectoras e iteradoras métodos selectores – ret NombreDelMetodo const; Objetos Dr. Dr.Deni DeniTorres TorresRomán: Román: La biblioteca iostream iostream vs stdio cout y cin objetos que permiten mediante el operador <<(>>) la salida o entrada de datos objetos flujos de datos Ejemplos – – – – cout<<“imprime un entero”<<15<<endl; cout<<“imprime un flotante”<<15.25<<endl; cout<<“imprime un letrero”<<endl; cout<<“imprime un hexadecimal”<<0xA5<<endl; Diferencias entre cout y printf Objetos 5 Asignación dinámica de memoria new En C existen las funciones malloc() y free() En C++ new asigna memoria dinámica – new tipo; // asigna un solo elemento – new tipo [ ]; // asigna un arreglo de elementos Ejemplos int n; char* s; cin>>n; int *p = new int; s = new char [n]; Point *p1= new Point(...); Objetos Liberación dinámica de memoria delete En C existe la función free() En C++ delete libera memoria dinámica – delete dirección; // libera un espacio // previamente asignado por new – delete[n] dirección; // idem para un arreglo de // elementos Ejemplos delete p; delete [ ] s; delete p1; Objetos 6 Ventajas de new y delete new conoce cuanta memoria se le asigna a cada variable, pero malloc( ) no, new invoca al constructor del objeto, mientras que malloc( ) no puede, delete invoca al destructor y libera memoria. siempre que use un new debe emplear en la parte correspondiente un delete para liberar memoria, p.e. constructor/destructor Objetos Funciones inline el compilador genera el código cada vez que encuentra esta función, es más segura que #define #define cuadrado (x) x*x – errónea si x= a+b sólo tiene sentido para funciones de código pequeño, aumenta la eficiencia del programa, no deben definirse donde se hace la definición de la clase, porque allí no debe haber código, Sintaxis – inline ret NombreDeFunción ( args ) { } Objetos 7 Declaraciones y definiciones en un archivo.h definiciones de tipo definiciones de funciones declaraciones de datos includes macro-definiciones comentarios declaraciones de clases struct point {...} extern int strlength(...) extern int a; #include <signal.h> #define .... /*...*/ // class clase {...}; Objetos Herencia y reusabilidad creación de clases a partir de otras para extender y reusar el código – los objetos pueden construirse de modo incremental a partir de otros objetos y pueden compartir código y estructuras de datos – los algoritmos generales se pueden escribir de modo que se puedan reusar para nuevos tipos de objetos organización jerárquica representación del polimorfismo Objetos Dr. Dr.Deni DeniTorres TorresRomán: Román: 8 Clases base y derivadas clases con similares atributos y operaciones pueden organizarse jerárquicamente la clase situada arriba de otras es base o superclase de las de abajo la clase situada abajo de otras es derivada o subclase ANIMAL Generalización Definición – proceso de extracción de todos los atributos y operaciones comunes en un conjunto de clases para crear una clase base o superclase Ejemplo – atributos: tipo, modelo, capacidad,... – operaciones: arrancar, parar, acelerar,... VEHICULO 9 Especialización Definición – proceso de refinamiento de clases en subclases o clases derivadas que heredan atributos y operaciones de la clase base o superclase Ejemplo Operación extra: flotar Atributo extra: Número de ruedas Terrestre Acuático Objetos Concepto de herencia simple Clase Base Clase Derivada 1 Clase Derivada 2 Clase Base Clase Base Objetos 10 Especificadores de acceso class B : public class A { }; los miembros public y protected de A pasan de igual forma a B class B : private class A { }; los miembros public y protected de A pasan en forma private a B class B : protected class A { }; los miembros public y protected de A pasan en forma protected a B Elementos en la herencia (I) private protected A public private A private B protected A protected B public A B public B Objetos 11 Elementos en la herencia (II) B hereda las funciones de A B hereda los datos de A las funciones propias de B no tienen acceso a los miembros private de A Objetos Concepto de herencia múltiple Clase B Clase A Clase Derivada AB Objetos 12 Relaciones multiniveles de herencia entre clases Clase A Clase C Clase B Clase D Clase E Objetos Elementos que no se heredan constructores destructores funciones friend funciones static datos static operador de asignación = Objetos 13 Conversiones de herencia un objeto de una clase derivada se convierte implícitamente en un objeto de una clase base pública, una referencia a una clase derivada se convierte implícitamente en una referencia a una clase base pública, un puntero a una clase derivada se convierte implícitamente en un puntero a una clase base pública. Objetos Dr. Dr.Deni DeniTorres TorresRomán: Román: Polimorfismo Sobrecarga de funciones Sobrecarga de operadores Funciones virtuales Funciones virtuales puras Objetos 14 Polimorfismo (I) una operación que puede tener más de un método es denominada polimórfica una operación se dice polimórfica si se comporta de forma diferente sobre clases diferentes la lista de argumentos, el tipo de retorno asociados con una operación constituyen el formato o signatura de la operación las operaciones polimórficas tienen el mismo nombre, la misma intención lógica y la misma signatura las operaciones polimórficas tienen o pueden tener código diferente en clases diferentes Objetos Polimorfismo (II) objetos de clases diferentes responden a un mismo mensaje u operación de forma también diferente – objetos de las clases circulo, triángulo, rectángulo, derivados de la clase forma, pueden responder a la función área() de forma diferente característica esencial del polimorfismo es que se puedan invocar funciones sin preocuparnos sobre qué tipo de objeto son invocadas construcción de estructuras heterogéneas de objetos debido a que un puntero a una clase base puede apuntar a cual objeto de clases derivadas el polimorfismo se implementa con funciones denominadas virtuales 15 Sobrecarga de funciones: polimorfismo ¿Qué es una función sobrecargada? Ejemplos – int suma (int a, int b); – string suma (string a, string b); Las funciones sobrecargadas tienen: – – – – el mismo nombre, un número diferente de argumentos, diferentes tipos de argumentos, ambas cosas Las funciones sobrecargadas pueden ser normales o miembros de una clase Objetos Ventajas de la sobrecarga de funciones uso del polimorfismo, menor número de nombres de funciones, sintaxis más clara, el compilador hace mucho de nuestro trabajo, enlace dinámico con funciones virtuales, llamadas en tiempo de ejecución. Objetos Dr. Dr.Deni DeniTorres TorresRomán: Román: 16 Sobrecarga de operadores en C++ significados de +: – suma de dos enteros – suma de dos reales si a y b son dos objetos definidos por el usuario, ¿será o no posible definir las operaciones de: – a = a + b; – a = a*b; ? la sobrecarga permite la validez de las expresiones anteriores. Con el operador + sobrecargado podríamos formar una cadena a partir de otras, p.e. – “Guadalajara” + “es la capital” + “de Jalisco.” tipos de operadores: – unarios – binarios Objetos Restricciones en los operadores sobrecargados de C++ se pueden sobrecargar sólo los operadores definidos en C++; no se pueden construir nuevos operadores la sobrecarga tiene validez sólo con objetos de la clase donde el operador está definido no se puede cambiar la preferencia o asociatividad de los operadores en C++ no se puede cambiar un operador binario para que funcione como uno unario y viceversa no se puede sobrecargar un operador que funcione exclusivamente con punteros la sobrecarga de ++ y -- no diferencia, en principio, pre- o postincremento Objetos 17 Sintaxis general de operator función miembro o método de la clase – class unTipo { private: atributos public: unTipo operator <op> (lista de argumentos); .... }; implementación del método o función miembro – unTipo unTipo::operator <op> (lista de argumentos) { cuerpo de la función } al menos un operando debe ser un tipo definido por el usuario, p.e. unTipo un operando puede ser un tipo básico Sobrecarga de operadores binarios (I) X1 + x2 se interpreta como – operator + ( x1, x2 ); // o como – x1.operator + ( x2 ); un operador unario se puede definir como: – una función miembro de un argumento – una función friend con dos argumentos class Binario { public: Binario operator <op> (Binario& ); }; Binario Binario::operator <op> (Binario& b ) { cuerpo } <op> puede ser +, *, -, /,... 18 Sobrecarga de operadores binarios (II) Ejemplo: – class unaClase { public: unaClase operator -(unaClase &t); unaClase operator -(int t); // unaClase- unaClase // unaClase- int }; – class unaClase { private: int undato; public: friend ostream& operator << ( ostream &, const unaClase & ); }; ostream& operator << ( ostream &out, const unaClase &t ) { out << “Salida en pantalla “<<endl<<“ dato privado =“ } << t.undato <<endl;Objetos Sobrecarga de operadores unarios ++ se interpreta como – operator ++ ( x ); // o como – x.operator ++ ( ); un operador unario se puede definir como: – una función miembro sin argumentos – una función friend con un argumento Ejemplo – class unaClase { public: unaClase& operator ++ ( void ); // ++unaClase }; – class unaClase { public: friend unaClase& operator ++ ( unaClase& ); Objetos }; //++ unaClase 19 Recomendaciones para sobrecargar los operadores es responsabilidad del programador definir correctamente el significado de las funciones sobrecargadas, pues C++ no interpreta automáticamente el significado de un operador sobrecargado C++ no deriva automáticamente el significado de un operador complejo, p.e.+=, no se puede cambiar la sintaxis de los operadores, p.e. + binario, ++ unario sólo se pueden sobrecargar los operadores indicados por C++ no se puede cambiar la precedencia o prioridad de los operadores Objetos Ejemplos de sobrecargas de operadores válidas y no válidas complejo operator + (complejo a, complejo b); //VAL void contador::operator++ (contador c) //VAL { } char* operator + (char* a, char* b); //NO VAL void operator@ (menu barra1, menu barra2); //NO VAL menu operator++ (menu barra1, menu barra2); //NO VAL Objetos 20 Sobrecarga del operador de asignación = el operador de asignación = puede sobrecargarse declarando una función miembro class string { string& operator = (string& str); }; si el operador = no se define por el usuario en una clase, entonces el compilador lo crea por defecto y realiza una asignación miembro a miembro x& x::operator = (const x& fuente) { cuerpo } Objetos Sobrecarga de los operadores de llamada a funciones ( ) y de subíndice [ ] y de flujo >> y << el operador ( ) puede emplearse para un tipo de subconjunto de la clase, p.e., un substring de la clase string – string string::operator( ) (int pos, int cont) el operador [ ] puede emplearse para extraer elementos específicos de un objeto de la clase, p.e., un caracter de un objeto de la clase string – char& string::operator[] (int elem) la sobrecarga de los operadores >> y << permite manipular además de los tipos de datos predefinidos, los tipos definidos por el usuario Objetos 21 El apuntador this el llamado a funciones se realiza siempre mediante un objeto – – – – objeto.funciónDeLaClase ( ); // o mediante un puntero punteroObjeto-> funciónDeLaClase ( ); ¿cómo se realiza esto? funciónDeLaClase ( this, argumentos ); en todo objeto existe un puntero al objeto llamado this this accesa a la dirección del propio objeto this permite accesar a los miembros del propio objeto – this ->nombreDeMiembro; *this es el objeto total real, no modificable Uso del this almacenar un puntero al objeto asociado con la invocación de una función miembro devolver una referencia al objeto asociado con la invocación de una función miembro T& T::f (int a ) código return *this; } hacer copias de un objeto referenciar explícitamente a un miembro oculto como resultado de otra declaración – – – – { class X { int longitud; public: X (int longitud){this -> longitud = longitud;} como argumento de una función 22 Constructor de copia Descripción – un constructor que crea un nuevo objeto a partir de uno existente Sintaxis class Point { int x, y; public: Point (int, int); Point (const Point&); ... }; Implementación Point::Point (const Point& p) x=p.x; y =p.y; { } Constructor de copia por defecto si no se incluye un constructor de copia el compilador crea uno automáticamente constructor de copia por defecto realiza las siguientes operaciones – void main() { – Point p1(1,2), p2(3,4), p3,; – Point p4(p2); p4.x = p2.x; p4.y = p2.y; //FUNCIONA MUY BIEN //SIN DEFINIRLO, ENTONCES? si un dato fuera un puntero, p.e., entonces se copia la dirección del puntero de la derecha en el miembro de la izquierda – p4.ptr = p2.ptr; – LOS DOS APUNTAN AL MISMO LUGAR!!! 23 Llamadas a los constructores de copia inicialización de un objeto con otro de la misma clase cuando se tiene una función con un argumento siendo un objeto cuando una función retorna un objeto Regla sobre el uso del constructor de copia – las clases con estructuras dinámicas de datos deben tener bien definido un constructor de copia, pues los constructores de copia por defecto sólo generan una copia superficial y no una copia profunda Dr. Dr.Deni DeniTorres TorresRomán: Román: Objetos Inicialización de objetos en C++ Los datos o miembros de un objeto se inicializan con valores la incialización se realiza en los constructores formas de inicializar – incialización mediante Ejemplo: class ObjetoIni { string s: char* dato; ObjetoIni (const string&, const char* iniCh); }; sentencias ObjetoIni::ObjetoIni (const string& iniStr, const char* iniCh){ s = iniStr; dato = iniCh;} lista de incialización ObjetoIni::ObjetoIni (const string& iniStr, const char* iniCh):s(iniStr, dato (iniCh){ } Objetos 24 Uso del operador = Ejemplo string a(“Hola”); sttring b(“Nada”); a =b; // Ahora a contiene la expresión “Nada” – el compilador creó el =, pero es una copia superficial !!! forma correcta de definirlo string& string::operator = (const string& s) { if (this ==&s) return *this; // a==a CASO IDENTIDAD delete [ ]str; //BORRAR VIEJO CONTENIDO long = s.long; if (s.str!=NULL){ str = new char [long+1]; //COPIA strcpy (str, s.str);} //NUEVA return *this; Objetos } Enlace estático y dinámico el enlace estático se realiza siempre que el compilador conoce con antelación el tipo de objeto – es rápida – es restrictiva Ejemplo: switch (codigo) { – case ´A´: exit (); – case ´B´: mostrar (); break; } el enlace dinámico se realiza siempre que el compilador desconoce la posición a invocar hasta el tiempo de ejecución – alto grado de flexibilidad – más lento que el estático – uso de funciones virtuales mediante la palabra virtual 25 Sobre las funciones virtuales (I) las funciones miembros de una clase pueden ser virtuales las funciones globales no pueden ser virtuales los destructores de las clases que van a ser heredadas deben declararse virtual para que sean llamados por los destructores de las clases derivadas ¿para qué? el uso de funciones virtuales puras posee gran utilidad, ¿por qué? en el interior de un constructor/destructor las funciones virtuales se llaman en tiempo de compilación una clase con una función virtual pura es una clase abstracta Sobre las funciones virtuales (II) la palabra clave virtual permite a una función ser definida en la clase base y en las clases derivadas bajo el mismo nombre una función sólo necesita ser declarada virtual en la clase base las funciones virtuales admiten los mismos argumentos, pero código diferente en clases también diferentes función virtual vacía – virtual void FuncionVacia ( ) { } función virtual pura – virtual void FuncionPura ( ) = 0; una función virtual pura no puede ser llamada en la clase base una función virtual pura sirve para declarar aquellas funciones cuya definición se pospone para las clases derivadas 26 Sobre las funciones virtuales (III) los constructores no pueden ser virtuales los destructores pueden y deben ser virtuales, lo cual permite que en una relación de herencia sean invocados todos los destructores una clase abstracta es aquella que tiene al menos una función virtual pura una clase abstracta sólo puede ser utilizada como clase base una clase abstracta se diseña sólo para ser heredada las clases abstractas son utilizadas sólo a través de punteros Objetos Polimorfismo en C++ crear una jerarquía de objetos con operaciones definidas como funciones virtuales en la clase base – virtual float Area ( ); si la clase base es tal que no se puede realizar implementaciones de estas funciones, entonces son funciones virtuales puras – virtual float Area ( ) = 0; – virtual float Area ( ) const = 0; hacer las implementaciones concretas en las clases derivadas; cada clase tiene una versión específica de la función virtual manipular las instancias de las clases a través de una referencia o un puntero para provocar el enlace dinámico Objetos 27 Problema Diseñar y elaborar un programa que represente un reloj con hrs, min y segs y un operator ++ que incremente el tiempo en segundos. Debe existir una clase base y clases derivadas para diferentes tipos de relojes. Manejarse además funciones virtuales. Objetos Casos de uso características – es una interacción entre un usuario y el sistema – captura alguna función visible al usuario – puede ser de distintos tamaños – satisface algún objetivo del usuario – organiza el sistema mediante actores y sus objetivos – utilidad en el análisis, diseño y pruebas Objetos 28 Casos de uso: partición del sistema subconjuntos de los requerimientos descripciones del comportamiento grupos de entidades comunicantes es fuente de las operaciones del sistema conjuntos de escenarios potenciales Objetos Casos donde las funciones virtuales se llaman en tiempo de compilación y no en tiempo de ejecución o corrida cuando una función virtual es llamada mediante – objeto.FuncionVirtual ( ); //se le asocia la función actual //de la clase base en llamadas dentro de los constructores y destructores, porque los objetos no están completamente inicializados Ejemplo: Objetos 29