P R O G R A M A C I Ó N Curso 0: Programación orientada a objetos (POO) Iván Alduán ([email protected]) ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 1 P R O G R A M A C I Ó N Introducción a C++ Introducción al entorno de Visual Studio Programación de pequeños ejemplos en C++ ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 3 Programación P R O G R A M A C I Ó N La programación es el proceso de diseñar, escribir, depurar y mantener el código fuente de programas computacionales Ficheros fuente y programa o código fuente Pensados para que los comprendan los seres humanos Lenguaje de programación de alto nivel: C/C++, Java, C#, … Ficheros objeto, código objeto y compiladores compilador = traduce el programa fuente a su código objeto equivalente (un fichero objeto por cada translation unit) Ficheros ejecutables, librerías y enlazadores Es necesario unir todos los ficheros objeto, más las librerías en un único fichero ejecutable (o librería) Link o enlazador = combina todos los ficheros que forman nuestro programa y crea el fichero ejecutable ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 4 Errores P R O G R A M A C I Ó N Errores de sintaxis Son errores en el programa fuente. Pueden deberse a palabras reservadas mal escritas, expresiones erróneas o incompletas El compilador nos dará una lista de errores de sintaxis Errores de enlazado El programa enlazador también puede encontrar errores, funciones que no están definidas en ninguno de los ficheros objetos ni en las librerías Puede que hayamos olvidado incluir alguna librería Errores de ejecución El programa terminará bruscamente Existen programas auxiliares para buscar estos errores, son los llamados depuradores (debuggers) Errores de diseño ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 5 IDEs y Microsoft Visual Studio P R O G R A M A C I Ó N Integrated Development Environment Proveen un marco de trabajo amigable con acceso a todas las herramientas necesarias para desarrollar programas Editor de código Resaltado de sintaxis, indicador de errores, autocompletado Compilador y Enlazador automáticos Si fallan te indican el motivo con bastante exactitud Depurador Ayuda a caminar a través de nuestro programa para detectar errores de ejecución: pila, breakpoint, watch Constructor de interfaces gráficas WYSIWIG (Plataforma .Net) Microsoft Visual Studio Versión Express gratuita (no plugins :/ ) Versión Professional gratuita a través de DreamSpark ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 6 La función main en C++ P R O G R A M A C I Ó N int main(int argc, char *argv[]) { int numero; numero = 2 + 2; return 0; } C++ es un superconjunto de C Aunque existen algunas diferencias entre ambos int main(): es la función que hace de punto de entrada del programa. Todo programa en C++ debe tener un función main ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 7 P R O G R A M A C I Ó N Example 01 – Hello World Comprobando que a todos nos funciona el IDE ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 8 Tipos de datos fundamentales C++ P R O G R A M A C I Ó N Heredados de C: void : no asociado a ningún tipo char : caracter int : entero float : número en coma flotante, precisión simple double : número en coma flotante, doble precisión Nuevos en C++: bool : tipo booleano wchar_t, char16_t, char32_t : caracter ancho (Unicode) Librería estándar de C++: std::string : cadenas de caracteres ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 9 Modificadores de tipos C++ P R O G R A M A C I Ó N ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 10 Operadores C++ P R O G R A M A C I Ó N Aritméticos: +, -, *, /, %, a++, ++a, a--, : suma, resta, multiplicación, división, resto --a : postincremento, preincremento, postdecremento Asignación: : asigna a x el valor de evaluar <<expresión>> +=, -=, *=, /= : suma, resta, multiplicación y división con asignación Ejemplo: a += b; es equivalente a: a = a + b; x = <<expresión>> Manejo de bits: : and, or, xor y not binarios << , >> : desplazamiento a izquierda y a derecha &, |, ^, ~ Lógicos: &&, ||, ! : and, or, not (devuelven un bool) ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 11 Operadores C++ P R O G R A M A C I Ó N Relacionales: >, >=, <, <=, ==, != : mayor, mayor o igual, menor, menor o igual, .. (devuelven un bool) de Preproceso: #define, #line, #pragma …. de Puntero: Operadores de indirección (*) y de referencia (&) Manejo de memoria: new y delete Otros: :: , .* , ->* , ? : , sizeof(), typeid() .... ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 12 Operadores C++ P R O G R A M A C I Ó N Precedencia Prioridad de unos operadores frente a otros Puede modificarse con paréntesis Asociatividad define el orden de ejecución para operadores con idéntica precedencia ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 13 Sentencias C++ P R O G R A M A C I Ó N Expresiones Declaración de variables <tipo> <identificador>; Asignación <variable> = <expresion>; Llamada a función <funcion>(<lista_parametros>); Bucles for (<inicializacion>; <condicion>; <incremento>) <sentencia> while (<condicion>) <sentencia> do <sentencia> while (<condicion>) Selección if (<condicion>) <sentencia1> else <sentencia2> switch (<variable) case <expresion>: <sentencia> ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 14 P R O G R A M A C I Ó N Example 02 – Múltiplos de 3 Usando diferentes tipos de sentencias ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 15 Funciones C++ P R O G R A M A C I Ó N En C++ es obligatorio usar prototipos. Un prototipo es una declaración de una función antes de ser utilizada dicha función Las funciones se deben definir en alguna parte, implementando su funcionalidad (cuerpo) Pueden estar en librerías externas, otros ficheros fuentes, etc //Declaración de la función int media(int, int); ... //Definición de la función int media(int a, int b) { int result; result = (a + b)/2; return result; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 16 Funciones C++ P R O G R A M A C I Ó N La estructura de un programa en C++ quedaría así ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 17 Funciones C++ Recursividad P R O G R A M A C I Ó N Una función es recursiva si durante su ejecución tiene una llamada a si misma Se distingue entre: Recursividad directa Recursividad indirecta: varias se llaman unas a otras formando ciclos Toda función recursiva ha de presentar al menos una condición de terminación Ejemplos: Cálculo del factorial mediante recursividad directa ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 18 P R O G R A M A C I Ó N Example 03 – Factorial Usando funciones, el debugger y la pila de llamadas ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 19 Ámbito de variables y funciones P R O G R A M A C I Ó N Una variable es global si se declara fuera de cualquier función. Se puede acceder a ella desde cualquier función Una variable global estática sólo es visible en la unidad de compilación en la que se declara Las variables locales se declaran dentro de una función o bloque, y solo son visibles desde el bloque donde se declaran Los parámetros de una función son variables locales Una variable local estática conserva el valor entre distintas llamadas a la función ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 20 Ámbito de variables y funciones P R O G R A M A C I Ó N /* Variables globales */ int i; int j = 10; float k, l; static char m; static int funcion_1() { /* Variables locales */ char d = ‘A’; static int call = 0; … call++; … return call; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 21 Conversión de tipos P R O G R A M A C I Ó N Implícita: En expresiones el tipo mas bajo promociona al mas alto long double > double > float > unsigned long long > long long > unsigned long > long > unsigned int > int > unsigned short > short > unsigned char > char En asignaciones el valor del lado derecho se convierte al tipo de la variable de la izquierda Explicita (casting) (tipo) expresion ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 22 Constantes C++ P R O G R A M A C I Ó N Varias formas de declararlas: Usando la directiva del preprocesador #define: #define MAX_SIZE 64 Usando un tipo enumerado: enum{ MAX_SIZE = 64, }; Usando const : const int MAX_SIZE = 64; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 23 Arrays C/C++ P R O G R A M A C I Ó N Son variables que contienen una colección consecutiva de datos Se declaran entre corchetes, y su tamaño debe ser fijado en tiempo de compilación Se accede a los elementos también entre corchetes. Los índices comienzan en 0, y no hay comprobación int a[10]; //array de 10 ints float b[2][10] //array de 2 dimensiones . . . a[0] = 10; b[1][4] = 5.3; a[20] = 123; //esto no da error de compilación ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 24 Inicialización de Arrays P R O G R A M A C I Ó N Al declarar un array se le puede dar valores iniciales a sus elementos: int int int int a[4] = {13, 1, 27, 1289}; b[] = {1, 3, 5, 7, 9}; c[4] = {23, 12}; //c[2] y c[3] sin inicializar d[2] = {12, 24, 91, 103}; //warning Si no se especifica el tamaño, tomará el del número de elementos inicializados. Si se inicializan menos del tamaño, los no inicializados tendrán basura. Si se inicializan más del tamaño, el compilador dará un aviso. ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 25 Punteros C/C++ P R O G R A M A C I Ó N Un puntero es una variable que representa una posición de memoria que contiene un dato Se declaran anteponiendo un * al nombre de la variable. Admiten el valor NULL (definido en cstdlib) int *a; // puntero a entero float *b; // puntero a flotante char *c; // puntero a caracter ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 26 Operadores de punteros P R O G R A M A C I Ó N Operaciones: El operador * dereferencia el puntero. Es decir, se accede al valor apuntado El operador & devuelve la dirección de memoria donde se encuentra una variable. Es decir se obtiene un puntero a la variable int a = 0; int *b; b = &a; // b apunta a la dirección donde está a *b = 127; // se guarda 127 en la dir. apuntada por b //En este punto la variable a tiene valor 127 ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 27 Operadores de punteros P R O G R A M A C I Ó N Operaciones: Los punteros se pueden sumar, restar, etc Esas operaciones se hacen en múltiplos del tamaño del dato apuntado int *a = . . . . //a apunta a algún lugar a = a + 1; //ahora apunta sizeof(int) más adelante // a apunta a la dir. del siguiente int en memoria a = a + 4; //ahora apunta 4*sizeof(int) más adelante ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 28 Arrays y punteros P R O G R A M A C I Ó N Los arrays se pueden comportar como punteros, y los punteros como arrays Una variable de tipo array es un puntero al primer elemento del array Un puntero al primer elemento de una colección consecutiva puede usarse como un array int a[16]; //array de 16 elementos *a = 10; // Es lo mismo que a[0] = 10; *(a + 3) = 20; // Es lo mismo que a[3] = 20; int *b = (int *) malloc (8*sizeof(int)); //b es un puntero a un espacio de memoria en el //que caben 8 ints b[6] = 123; // Es lo mismo que *(b + 6) = 123; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 29 Arrays y punteros P R O G R A M A C I Ó N Diferencias: Un array tiene un tamaño asociado, un puntero no Un array es como un puntero constante, no se puede cambiar el lugar al que apunta Un array está definido en memoria estática y un puntero puede apuntar a memoria dinámica int a[16]; //array de 16 elementos int s1 = sizeof(a); //s1 valdrá 16*sizeof(int) int *b = (int *) malloc (128*sizeof(int)); //b es un puntero a una colección de 128 int int s2 = sizeof(b); //s2 valdrá 4 u 8, que es el //tamaño de una dirección ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 30 Memoria dinámica P R O G R A M A C I Ó N Stack o Pila (Memoria estática) Variables locales (dentro de un bloque) Va aumentando acumulando bloques de variables encima a medida que entramos a más funciones El programa la gestiona automáticamente (FIFO) Tamaño muy limitado (1MB – 32MB) Heap o Montículo (Memoria dinámica) Grueso de memoria no utilizado por ningún programa Podemos reservar memoria dinámicamente Enorme cantidad de memoria Tenemos que gestionarla los programadores ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 31 malloc y free (C/C++) P R O G R A M A C I Ó N Ejemplo: int *a, *b; // punteros a enteros //se reserva espacio en memoria para un entero //a apunta a ese espacio de memoria a = (int *) malloc (1*sizeof(int)); //se reserva espacio en memoria para 16 enteros //b apunta a ese espacio de memoria b = (int *) malloc (16*sizeof(int)); //se libera el espacio del primer malloc free(a); //se libera el espacio del segundo malloc free(b); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 32 new y delete (C++) P R O G R A M A C I Ó N Para realizar esta administración de la memoria dinámica, C++ cuenta con dos operadores new y delete El operador new reserva memoria dinámica para cualquier tipo tipos primitivos (int, double) tipos definidos por el usuario (clases o registros) delete se encarga de liberar la memoria previamente reservada Pueden aplicarse para reservar elementos individuales o arrays int *a, *b; a = new int; b = new int[100000000]; delete a; delete[] b; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 33 P R O G R A M A C I Ó N Example 04 – Ordenación de un vector Usando watch para inspeccionar el valor de punteros ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 34 Registros C++ P R O G R A M A C I Ó N Son tipos compuestos formados por elementos heterogéneos Dentro del registro cada elemento tiene un identificador y un tipo. //Definición del registro struct Complejo { float real; float imag; }; //Declaración de variables del tipo registro Complejo uncomplejo, otrocomplejo; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 35 Registros C++ P R O G R A M A C I Ó N Para acceder a los elementos de un registro estructura se utiliza el operador punto (.) uncomplejo.real = 1.3; uncomplejo.imag = 2.7; Si se trata de un puntero a registro se puede atajar con el operador flecha (->) Complejo *a = (Complejo *)malloc(sizeof(Complejo)); a->real = 2.4; //lo mismo que (*a).real = 2.4; a->imag = 3.14; //lo mismo que (*a).imag = 3.14; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 36 std::strings (C++) P R O G R A M A C I Ó N En C++ si existe un tipo de datos para strings También se utilizan arrays de char acabados con el caracter ‘\0’ como en C Una cadena de caracteres entre comillas dobles es un inmediato que representa un string #include<cstring> std::string s = “Esto es un tipo cadena”; char s1[] = “Hola”; char *s2 = “Hola”; char *s3[] = {‘H’, ‘o’, ‘l’, ‘a’, ‘\0’} std::string s4(s1); // convertir a string int n = s4.length(); // longitud de la cadena ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 37 Argumentos de funciones (C++) P R O G R A M A C I Ó N Los argumentos por defecto siempre se pasan por valor Pasar un argumento por valor copia todo su contenido No se deben pasar nunca objetos pesados por valor Podríamos pasar punteros a los objetos Con paso por referencia la sintaxis es mucho más amigable sin tener que aplicar los operadores de punteros Internamente funcionan como punteros //Ejemplo de paso de argumentos por referencia void intercambia(int &a, int &b) { int aux = a; a = b; b = aux; } int x = 10, y = 20; Intercambia(x, y); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 38 P R O G R A M A C I Ó N Example 05 – Palíndromos Operando con std::string ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 39 Espacios con nombre (C++) P R O G R A M A C I Ó N namespace mathlib { int max(int a, int b); int min(int a, int b); struct Vector { float x, y, z; }; ... } Nos ayudan a evitar problemas con identificadores iguales en grandes proyectos Diferentes librerías puede que usen los mismos nombres para cosas diferentes, de modo que resulta imposible integrar esas librerías en la misma aplicación ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 40 Espacios con nombre (C++) P R O G R A M A C I Ó N El nombre del espacio funciona como un prefijo para las variables, funciones o clases declaradas en su interior Para acceder a una de esas variables se tiene que Usar un especificador de ámbito (::) activar el espacio con nombre adecuado mathlib::vector v; int n = mathlib::max(10, 15); using namespace mathlib; Vector w; int m = min(10, 15); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 41 Librerías externas en Windows P R O G R A M A C I Ó N Una librería es un conjunto de recursos (algoritmos) prefabricados, que pueden ser utilizados por el programador para realizar determinadas operaciones Windows: librerías estáticas (.lib) y librerías dinámicas (.dll) MSBUILD: librerías de importación (.lib) Necesitamos tres cosas Archivos de definición o includes Las librerías a importar dentro de nuestro programa (.lib) Si procede, que el programa tenga acceso a la librería dinámica cuando entre en ejecución (.dll) Mismo directorio que el ejecutable PATH del sistema operativo ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 42 P R O G R A M A C I Ó N Example 06 – GLUT Cube Usando librerías externas y pintando gráficos 3D ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 43 Bibliografía recomendada P R O G R A M A C I Ó N S.B. Lippman – C++ Primer (5th) – 2012 B. Stroustrup – The C++ Programming Language (4th) – 2013 ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 44 P R O G R A M A C I Ó N Programación orientada a objetos (POO) ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 45 Programación Orientada a Objetos P R O G R A M A C I Ó N La programación orientada a objetos es una forma de programar que trata de encontrar una solución más intuitiva para la resolución de problemas complejos Exige un cambio de mentalidad para diseñar aplicaciones y programas informáticos ahora más complejos No buscamos directamente el encontrar la secuencia exacta de las instrucciones necesarias para resolver el problema Queremos abstraernos a un nivel más conceptual para dividir el problema en una serie de elementos que interaccionando entre sí den solución al problema La idea básica de este tipo de programación es agrupar los datos y los procedimientos para manejarlos en entidades únicas con un significado a las que llamaremos objetos Un programa es un objeto, que a su vez está formado de otros objetos que interactúan entre sí ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 46 Objeto P R O G R A M A C I Ó N Un objeto es una unidad con cierto significado que engloba en sí mismo: Un conjunto de datos que definen su estado Los procedimientos necesarios para el tratamiento de esos datos con facilidad Ejemplos de objetos del inundo real son: pasajero, asiento, avión, vuelo, aeropuerto Por ejemplo, los atributos de un pasajero incluyen el nombre, la edad, el sexo, la fecha de nacimiento, la dirección, etc El comportamiento es el conjunto de cosas que puede hacer un objeto; por ejemplo, un pasajero puede estudiar, trabajar, comer, dormir, etc ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 47 Objeto P R O G R A M A C I Ó N Posible ejemplo de un objeto dentro de una aplicación encargada de gestionar unos cines Otros objetos en la aplicación podrían ser cine, empleado, sala, proyector, butaca, espectador, entrada ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 48 Objeto: conceptos P R O G R A M A C I Ó N Propiedades o atributos: Características o variables que definen a un objeto Métodos: Funciones disponibles en el objeto para manipular o modificar los atributos del mismo Mensaje: El mensaje es el modo en el que se comunican los objetos entre sí En realidad, esto no es mas que una llamada a un método de un determinado objeto ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 49 Programa OO vs OP P R O G R A M A C I Ó N El resultado final del proceso es un programa de computadora que contiene características que representan algunos de los objetos del mundo real que son parte del suceso ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 50 Ventajas P R O G R A M A C I Ó N Ventajas de la programación orientada a objetos Diseños más cercanos al mundo real Más fáciles de diseñar y mantener Facilidad de comunicación entre todos los roles implicados en el desarrollo: usuarios, clientes, analistas, diseñadores, programadores Facilita la reutilización de código ya que cada objeto tiene significado propio Cada objeto es independiente del resto Ejemplo: Una clase Vector3 la podremos reutilizar en todas nuestras aplicaciones de gráficos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 51 Clases P R O G R A M A C I Ó N Una clase define un patrón para construir objetos Es importante distinguir entre objetos y clases La clase es simplemente una declaración, patrón o tipo Los objetos son los ejemplares concretos de una clase. Cuando creamos un ejemplar tenemos que especificar la clase a partir de la cual se creará Por ejemplo, un objeto de la clase película sería Toy Story ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 52 Clases en C++ P R O G R A M A C I Ó N Las clases C++ permiten definir nuevos tipos de datos Cada clase es un nuevo tipo Cada elemento de la clase se caracteriza por ciertos valores y las operaciones disponibles para crear dichos elementos, modificarlos y destruirlo Podemos establecer un paralelismo entre los tipos de datos vistos hasta el momento (int, char, array, struct, …) y las clases Ambos son tipos Pueden declararse elementos de ese tipo En los tipos por defecto los llamábamos variables En el caso de una clase los llamaremos instancias u objetos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 53 Clases en C++ P R O G R A M A C I Ó N Características fundamentales de las clases en C++ Nombre de la clase. Sirve para identificar a todos los objetos que tengan unas determinadas características Conjunto de atributos. Datos miembro. El valor de los atributos representan el estado de cada objeto. Conjunto de métodos. Funciones miembro. Permite que los objetos cambien de estado, dependiendo del estado anterior que tuviera el objeto. Niveles de acceso para proteger ciertos miembros de la clase. Normalmente, se definirán como ocultos (privados) los atributos y visibles (públicos) los métodos. ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 54 Declaración de clases en C++ P R O G R A M A C I Ó N ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 55 Paso de mensajes P R O G R A M A C I Ó N Una vez creados los objetos, podemos trabajar con ellos. Si queremos que un determinado objeto ejecute un método, utilizamos el operador punto (•). A esto se le conoce como paso de mensajes. Cada paso de mensaje provoca la ejecución del correspondiente método definido en la clase del objeto receptor Cada objeto entiende tantos mensajes como métodos estén definidos en su clase ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 56 Ocultación / Encapsulamiento P R O G R A M A C I Ó N La clave de la programación orientada a objetos es el encapsulamiento de todo el código y detalles de implementación bajo interfaces de manejo sencillo La definición de una clase en C++ viene dada por: Un archivo de cabecera (.h) Define la interfaz de la clase de forma clara, es decir, qué métodos ofrece el módulo definido, sin detalles de implementación Un archivo fuente (.cpp) Define los detalles de implementación de la clase Inclusión de su correspondiente fichero de cabecera (#include) Definición de funciones declaradas y no declaradas en el fichero de cabecera ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 57 Especificadores de acceso P R O G R A M A C I Ó N Dentro de la lista de miembros, cada miembro puede tener diferentes niveles de acceso class <identificador de clase> { public: <lista de miembros> private: <lista de miembros> protected: <lista de miembros> }; Public: miembros accesibles desde cualquier parte Private: sólo son accesibles por la propia clase Protected: nos faltan conocimientos para entenderlo ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 58 Especificadores de acceso P R O G R A M A C I Ó N Por lo general Los atributos deben ser privados Los métodos o funciones miembro deben ser públicas A través del objeto de una clase sólo se puede acceder a lo que está declarado como público en la clase Lo privado solo puede ser manipulado internamente desde el código de los métodos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 59 El puntero this P R O G R A M A C I Ó N Todos los objetos de una clase comparten la misma copia de las funciones de esa clase ¿cómo hace una función miembro para referirse a un dato de un objeto en concreto? La respuesta es: usando el puntero this cada objeto tiene asociado un puntero a si mismo que se puede usar para manejar sus miembros generalmente su uso es transparente al programador, pero a veces es necesario invocarlo de manera explícita void pareja::Guarda(int a_input, int b) { a = a_input; // equivale a this->a = a_input; this->b = b; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 60 Diseño conceptual P R O G R A M A C I Ó N Para representar gráficamente las clases y objetos, se utilizan diagramas conceptuales basados en UML (Lenguaje de Modelado Unificado) ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 61 Resumen P R O G R A M A C I Ó N Las instancias de un tipo cualquiera se denominan variables, mientras que las instancias de una clase se denominan objetos Los atributos describen el estado de un objeto. Un atributo consta de dos partes: nombre del atributo y valor. Los métodos describen el comportamiento de los objetos de una clase. Representan las operaciones que se pueden realizar con los objetos de la clase. La ejecución de un método puede conducir a cambiar el estado del objeto. Los objetos se manipulan mediante el paso de mensajes. Para ejecutar un método asociado a un objeto, se realiza una acción que se conoce como “envío de mensajes”. Se denomina encapsulamiento al ocultamiento del estado, es decir, de los datos miembro, de un objeto Las operaciones y datos visibles desde el exterior de la clase es lo que se denomina interfaz de la clase ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 62 El poder de la POO P R O G R A M A C I Ó N Constructores y destructores Sobrecarga de operadores y métodos Métodos estáticos Herencia Interfaces Clases abstractas Funciones virtuales Polimorfismo Plantillas Excepciones ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 63 Constructores P R O G R A M A C I Ó N Los constructores son funciones miembro especiales que sirven para inicializar un objeto Tienen el mismo nombre que la clase, no retornan ningún valor y no pueden ser heredados Por norma general deben ser públicos ya que siempre se usan desde el exterior de la clase en un patrón de diseño singleton precisamente nos interesa lo contrario, que el constructor esté oculto Si no declaramos ningún constructor, el compilador lo hará por nosotros creando uno por defecto ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 64 Constructores P R O G R A M A C I Ó N Ejemplo: class pareja { public: // Constructor pareja(int a2, int b2); // Funciones miembro de la clase "pareja" void Lee(int &a2, int &b2); void Guarda(int a2, int b2); private: // Datos miembro de la clase "pareja" int a, b; public: }; pareja::pareja(int a2, int b2) { a = a2; b = b2; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 65 Constructores P R O G R A M A C I Ó N Cuando se use un constructor sin parámetros para declarar un objeto no se deben escribir los paréntesis error frecuente cuando se empiezan a usar clases Si un constructor requiere argumentos, es obligatorio suministrarlos pareja par1(12,43); pareja par2(45,34); pareja par1(); //ERROR -> El compilador piensa que es un //prototipo de una función pareja par1; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 66 Constructores P R O G R A M A C I Ó N Hay un modo más seguro de inicializar los datos miembros de los objetos en los constructores Inicializadores: Cada inicializador consiste en el nombre de la variable miembro a inicializar, seguida de la expresión que se usará para inicializarla entre paréntesis pareja::pareja(int a2, int b2) : a(a2), b(b2) {} Pregunta: ¿Qué pasa si dentro de nuestra clase tenemos como atributo un objeto sin constructor por defecto? ¿Eficiencia? ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 67 Constructores P R O G R A M A C I Ó N Sobrecarga de constructores podemos definirse varios constructores para cada clase pareja(int a2, int b2) : a(a2), b(b2) {} pareja() : a(0), b(0) {} Argumentos por defecto reducir el número de constructores necesarios pareja(int a2=0, int b2=0) : a(a2), b(b2) {} ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 68 Constructores P R O G R A M A C I Ó N Constructor copia crea un objeto a partir de otro objeto existente un argumento que es una referencia a un objeto de su misma clase si no se define, el compilador crea uno por defecto pareja(const pareja &p); pareja::pareja(const pareja &p) : a(p.a), b(p.b) {} Asignación de objetos copia los valores de los datos miembro pareja par1(12, 32), par2; par2 = par1; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 69 Destructores P R O G R A M A C I Ó N Los destructores son funciones miembro especiales que sirven para definir cómo se elimina un objeto de una determinada clase Tienen el mismo nombre que la clase, pero con el símbolo ~ delante, no retornan ningún valor y no pueden ser heredados En general, será necesario definir un destructor cuando nuestra clase tenga datos miembro de tipo puntero Pregunta: ¿Tiene sentido la sobrecarga de destructores? ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 70 Ejemplo: Clase cadena P R O G class cadena { public: cadena(char *c); cadena(const cadena &); ~cadena(); R A M A C I Ó N // ¿Por qué es necesario definirlo? // ¿Por qué es necesario definirlo? void Set(char *dest); char* Get(); private: char *cad; // cadena de caracteres }; cadena::cadena(char *c) { cad = new char[strlen(c)+1]; strcpy(cad, c); // Almacena la cadena } … ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 71 Ejemplo: Clase cadena P R O G R A M A C I Ó N … cadena::~cadena() { delete[] cad; // Libera la memoria reservada a cad } cadena::cadena(const cadena &c) { if(&c == this) { cout << "Sí, soy yo." << endl; this->cad = c.cad; } else { cout << "No, no soy yo." << endl; this->cad = new char[strlen(c.cad)+1]; strcpy(this->cad, c.cad); } return c; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 72 Operadores sobrecargados P R O G R A M A C I Ó N Podemos redefinir cualquier operando aplicado a una clase para que funcione como nosotros deseemos Cuando se sobrecargan operadores en el interior de una clase se asume que un operando es el propio objeto de la clase por lo que no hay que declararlo Cuando nuestra clase tenga punteros es posible que necesitemos sobrecargar el operador asignación (=) Pensar en los problemas anteriores del constructor copia por defecto ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 73 Sobrecarga de operadores P R O G R A M A C I Ó N class Tiempo { public: Tiempo(int h=0, int m=0) : hora(h), minuto(m) {} Tiempo operator+(const Tiempo &h); Tiempo operator*(const Tiempo &h); ¿tiene sentido? private: int hora; int minuto; }; Tiempo Tiempo::operator+(const Tiempo &h) { Tiempo temp; temp.minuto = minuto + h.minuto; temp.hora = hora + h.hora; if(temp.minuto >= 60) { temp.minuto -= 60; temp.hora++; } return temp; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 74 Operadores sobrecargados P R O G R A M A C I Ó N Problema: ¿Cómo sobrecargamos un operador unitario sufijo? class Tiempo { ... Tiempo& operator++(); ... }; Tiempo& Tiempo::operator++() { minuto++; while(minuto >= 60) { minuto -= 60; hora++; } return *this; } Tiempo t1; ++t1; ¿t1++;? ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 75 Operadores sobrecargados P R O G R A M A C I Ó N Problema: ¿Cómo sobrecargamos el operador unitario sufijo? no hay forma de decirle al compilador cuál de las dos modalidades del operador estamos sobrecargando, así que los compiladores usan una regla: si se declara un parámetro para un operador ++ ó – se sobrecargará la forma sufija del operador Tiempo Tiempo::operator++(int) { Tiempo temp(*this); // Constructor copia minuto++; while(minuto >= 60) { minuto -= 60; hora++; } return temp; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 76 Métodos sobrecargados P R O G R A M A C I Ó N Sobrecarga de métodos Las funciones miembros de las clases también pueden sobrecargarse Argumentos por defecto En las funciones miembros de las clases también pueden usarse parámetros con valores por defecto void Vector3D::Asignar(float xi, float yi=0, float zi=0) { x = xi; y = yi; z = zi; } void Vector3D::Asignar(const Vector3D &p) { Asignar(p.x, p.y, p.z); } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 77 Sistema de protección P R O G R A M A C I Ó N Especificadores de acceso public: private: protected: Declaraciones friend El modificador "friend" puede aplicarse a clases o funciones para inhibir el sistema de protección Las relaciones de "amistad" entre clases son parecidas a las amistades entre personas: la amistad no puede transferirse, si A es amigo de B, y B es amigo de C, esto no implica que A sea amigo de C la amistad no puede heredarse. Si A es amigo de B, y C es una clase derivada de B, A no es amigo de C la amistad no es simétrica. Si A es amigo de B, B no tiene por qué ser amigo de A ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 78 Sistema de protección P R O G R A M A C I Ó N Ejemplo: funciones amigas externas class A { public: A(int i=0) : a(i) {} private: int a; friend void Ver(A); // "Ver" es amiga de la clase A }; void Ver(A Xa) { // La función Ver puede acceder a miembros privados // de la clase A, ya que ha sido declarada "amiga" de A cout << Xa.a << endl; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 79 Sistema de protección P R O G R A M A C I Ó N Ejemplo: funciones amigas en otras clases class A; // Declaración previa (forward) class B { public: B(int i=0) : b(i) {} void Ver() { cout << b << endl; } bool EsMayor(A Xa); // Compara b con a private: int b; }; class A { public: A(int i=0) : a(i) {} void Ver() { cout << a << endl; } private: // Función amiga tiene acceso a miembros privados de la clase A friend bool B::EsMayor(A Xa); int a; }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 80 Sistema de protección P R O G R A M A C I Ó N Ejemplo: clases amigas /* Clase para elemento de lista enlazada */ class Elemento { public: Elemento(int t); int Tipo() { return tipo;} private: int tipo; Elemento *sig; // siguiente elemento friend class Lista; // amistad con lista }; /* Clase para lista enlazada de números*/ class Lista { . . . } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 81 Modificadores de miembros P R O G R A M A C I Ó N Funciones miembro inline El código generado para esa función cuando el programa se compila, se inserta en todos los punto donde se invoca a la función, en lugar de hacerlo en otro lugar y hacer llamadas Hay dos maneras de declarar una función como inline: Las funciones que se definen dentro de la declaración de la clase son inline implícitamente La otra forma es hacerlo explícitamente class Ejemplo { public: Ejemplo(int a = 0); private: int A; }; inline Ejemplo::Ejemplo(int a) : A(a) {} ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 82 Modificadores de miembros P R O G R A M A C I Ó N Funciones miembro const Cuando una función miembro no modifique el valor de ningún dato de la clase, podemos y debemos declararla como constante si la función intenta modificar el objeto el compilador generará un error class Ejemplo2 { public: Ejemplo2(int a = 0) : A(a) {} void Modifica(int a) { A = a; } // Error si se declara constante int Lee() const { return A; } private: int A; }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 83 Modificadores de miembros P R O G R A M A C I Ó N Otros usos de const valores de retorno constantes de las funciones paso de parámetros constantes a funciones const Vector Vector::operator+( const Vector &other ) const { Vector result; result.x = this->x + other.x; result.y = this->y + other.y; result.z = this->z + other.z; return result; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 84 Modificadores de miembros P R O G R A M A C I Ó N Miembros static de una clase Son miembros que no dependen de un objeto o instancia concreto sino que funcionan a nivel de clase En el caso de los atributos static sólo existirá una copia que compartirán todos los objetos de la misma clase Es necesario inicializar los datos estáticos de una clase Las funciones static no pueden acceder a los miembros de los objetos, sólo pueden acceder a los datos miembro de la clase que sean static ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 85 Modificadores de miembros P R O G R A M A C I Ó N Ejemplo: class Singleton { public: static Singleton* Instance(); private: Singleton(); Singleton(const Singleton &); Singleton &operator= (const Singleton &); static Singleton* pinstance; }; Singleton* Singleton::pinstance = NULL;// Inicializa el miembro static Singleton* Singleton::Instance () { if (pinstance == NULL) pinstance = new Singleton; // ¿Es la primera llamada? // Creamos la instancia return pinstance; } Singleton *obj = Singleton::Instance(); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 86 P R O G R A M A C I Ó N Example 07 – GLUT orientado a objetos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 87 Herencia P R O G R A M A C I Ó N Nos permite crear nuevas clases a partir de clases existentes, conservando las propiedades de la clase original y añadiendo otras nuevas La nueva clase obtenida se conoce como clase derivada, y las clases a partir de las cuales se deriva, clases base cada clase derivada puede usarse como clase base para obtener una nueva clase derivada y cada clase derivada puede serlo de una o más clases base ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 88 Herencia P R O G R A M A C I Ó N Esto nos va a permitir crear jerarquías de clases tan complejas como nos sea necesario ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 89 Herencia P R O G R A M A C I Ó N Un ejemplo muy común es de las personas todas las personas tienen propiedades comunes, nombre, fecha de nacimiento, género, estado civil, etc. dividimos a todas las personas en dos grandes clases: empleados y estudiantes los ingresos por nómina son exclusivos de los empleados la nota media del curso es exclusiva de los estudiantes ahora podemos clasificar a los empleados en ejecutivos y comerciales …. ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 90 Herencia P R O G R A M A C I Ó N Ahora podemos ver las ventajas de disponer de una jerarquía completa de clases Cada vez que creemos un objeto de cualquier tipo derivado este tendrá las propiedades de todos sus tipos base Siempre podremos crear nuevas clases para resolver nuevas situaciones Podemos aplicar procedimientos genéricos a una clase en concreto sin tener en cuenta que tipo de subclase es ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 91 Herencia P R O G R A M A C I Ó N Ejemplo: // Clase base Persona: class Persona { public: Persona(char *n, int e); const char *LeerNombre(char *n) const; int LeerEdad() const; void CambiarNombre(const char *n); void CambiarEdad(int e); protected: char nombre[40]; int edad; }; // Clase derivada Empleado: class Empleado : public Persona { public: Empleado(char *n, int e, float s); float LeerSalario() const; void CambiarSalario(const float s); protected: float salarioAnual; }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 92 Herencia P R O G R A M A C I Ó N Para cada clase base podemos definir dos tipos de acceso, public o private. Si no se especifica ninguno de los dos, por defecto se asume que es private public: los miembros heredados de la clase base conservan el tipo de acceso con que fueron declarados en ella private: todos los miembros heredados de la clase base pasan a ser miembros privados en la clase derivada Usar el acceso protected nos permite que los datos sean inaccesibles desde el exterior de las clases, pero a la vez, permite que sean accesibles desde las clases derivadas ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 93 Herencia P R O G R A M A C I Ó N Constructores en clases derivadas Cuando se crea un objeto de una clase derivada, primero se invoca al constructor de la clase base y a continuación al constructor de la clase derivada Si el constructor base no tiene parámetros la llamada se realiza de forma automática Si el constructor base necesita parámetros, tenemos que encargarnos nosotros de llamar al constructor base ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 94 Herencia P R O G R A M A C I Ó N Ejemplo: class ClaseA { public: ClaseA(int a) : datoA(a) { cout << "Constructor de A" << endl; } int LeerA() const { return datoA; } protected: int datoA; }; class ClaseB : public ClaseA { public: ClaseB(int a, int b) : ClaseA(a), datoB(b) { (1) cout << "Constructor de B" << endl; } int LeerB() const { return datoB; } protected: int datoB; }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 95 Herencia P R O G R A M A C I Ó N Destructores en clases derivadas Cuando se destruye un objeto de una clase derivada, primero se invoca al destructor de la clase derivada, si existen objetos miembro a continuación se invoca a sus destructores y finalmente al destructor de la clase base class ClaseB : public ClaseA { public: ClaseB() : datoB(20) { cout << "Constructor de B" << endl; } ~ClaseB() { cout << "Destructor de B" << endl; } int LeerB() const { return datoB; } protected: int datoB; }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 96 Polimorfismo P R O G R A M A C I Ó N En una clase derivada se puede definir una función que ya existía en la clase base, esto se conoce como "overriding", o superposición de una función La definición de la función en la clase derivada oculta la definición previa en la clase base Podemos acceder a la función de la clase base mediante una sintaxis un tanto especial Superposición Cuando se superpone una función, se ocultan todas las funciones con el mismo nombre en la clase base ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 97 Polimorfismo P R O G R A M A C I Ó N Ejemplo: class ClaseA { public: ClaseA() : datoA(10) {} int LeerA() const { return datoA; } void Mostrar() { cout << "a = " << datoA << endl; } protected: int datoA; }; class ClaseB : public ClaseA { public: ClaseB() : datoB(20) {} int LeerB() const { return datoB; } void Mostrar() { cout << "a = " << datoA << ", b = “ << datoB << endl; } protected: int datoB; }; ClaseB objeto; objeto.Mostrar(); objeto.ClaseA::Mostrar(); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 98 Polimorfismo P R O G R A M A C I Ó N C++ nos permite acceder a objetos de una clase derivada usando un puntero a la clase base Por supuesto, sólo podremos acceder a datos y funciones que existan en la clase base, los datos y funciones propias de los objetos de clases derivadas serán inaccesibles Con lo que hemos visto hasta ahora, si accedemos a objetos de una clase derivada usando un puntero a la clase base, se ejecuta el código de la clase base ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 99 Polimorfismo P R O G R A M A C I Ó N Ejemplo: class Persona { public: Persona(char *n) { strcpy(nombre, n); } void VerNombre() { cout << nombre << endl; } protected: char nombre[30]; }; class Empleado : public Persona { public: Empleado(char *n) : Persona(n) {} void VerNombre() { cout << "Emp: " << nombre << endl; } }; class Estudiante : public Persona { public: Estudiante(char *n) : Persona(n) {} void VerNombre() { cout << "Est: " << nombre << endl; } }; Persona *Pepito = new Estudiante("Jose"); Persona *Carlos = new Empleado("Carlos"); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 100 Polimorfismo P R O G R A M A C I Ó N Sería mucho más interesante que cuando se invoque a una función que se superpone en la clase derivada, se llame a ésta última función, la de la clase derivada Esto se consigue mediante el uso de funciones virtuales cuando en una clase declaramos una función como virtual, y la superponemos en alguna clase derivada, al invocarla usando un puntero de la clase base, se ejecutará la versión de la clase derivada ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 101 Polimorfismo P R O G R A M A C I Ó N Ejemplo: class Persona { public: Persona(char *n) { strcpy(nombre, n); } virtual void VerNombre() { cout << nombre << endl; } protected: char nombre[30]; }; class Empleado : public Persona { public: Empleado(char *n) : Persona(n) {} void VerNombre() { cout << "Emp: " << nombre << endl; } }; class Estudiante : public Persona { public: Estudiante(char *n) : Persona(n) {} void VerNombre() { cout << "Est: " << nombre << endl; } }; Persona *Pepito = new Estudiante("Jose"); Persona *Carlos = new Empleado("Carlos"); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 102 Polimorfismo P R O G R A M A C I Ó N También funciona con referencias Estudiante Pepito("Jose"); Empleado Carlos("Carlos"); Persona &rPepito = Pepito; // Referencia como Persona Persona &rCarlos = Carlos; // Referencia como Persona rCarlos.VerNombre(); rPepito.VerNombre(); Una vez que una función es declarada como virtual, lo seguirá siendo en las clases derivadas, es decir, la propiedad virtual se hereda ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 103 Polimorfismo P R O G R A M A C I Ó N 1. Supongamos que tenemos una estructura de clases en la que en alguna de las clases derivadas exista un destructor… 2. si destruimos un objeto referenciado mediante un puntero a la clase base, y el destructor no es virtual, estaremos llamando al destructor de la clase base… 3. ¡Esto puede ser desastroso! Destructores virtuales debemos respetar siempre ésta regla: si en una clase existen funciones virtuales, el destructor debe ser virtual ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 104 Polimorfismo P R O G R A M A C I Ó N 1. accedemos a un objeto de una clase derivada usando una referencia a la clase base … 2. llamamos al constructor copia para crear una nueva copia de esa clase… 3. ¡Estamos llamando al constructor copia de la clase base para copiar una clase derivada! Constructores virtuales Los constructores no pueden ser virtuales Si un constructor llama a una función virtual, ésta será siempre la de la clase base (la clase derivada aún no se ha creado) Para solucionar este inconveniente se suele crear una función virtual "clonar" en la clase base que se superpondrá para cada clase derivada ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 105 Polimorfismo P R O G R A M A C I Ó N Ejemplo: class Persona { public: Persona(char *n) { strcpy(nombre, n); } Persona(const Persona &p); virtual Persona* Clonar() { return new Persona(*this); } protected: char nombre[30]; }; class Empleado : public Persona { public: Empleado(char *n) : Persona(n) {} Empleado(const Empleado &e); virtual Persona* Clonar() { return new Empleado(*this); } }; class Estudiante : public Persona { public: Estudiante(char *n) : Persona(n) {} Estudiante(const Estudiante &e); virtual Persona* Clonar() { return new Estudiante(*this); } }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 106 Clases abstractas P R O G R A M A C I Ó N Funciones virtuales puras Una función virtual pura es aquella que no necesita ser definida El modo de declarar una función virtual pura es asignándole el valor cero class Persona { public: Persona(char *n) { strcpy(nombre, n); } virtual void Mostrar() = 0; protected: char nombre[30]; }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 107 Clases abstractas P R O G R A M A C I Ó N Clase abstracta Una clase abstracta es aquella que posee al menos una función virtual pura No es posible crear objetos de una clase abstracta, estas clases sólo se usan como clases base para la declaración Las funciones virtuales puras serán aquellas que siempre se definirán en las clases derivadas, de modo que no se necesita implementación base Siempre hay que definir todas las funciones virtuales de una clase abstracta en sus clases derivadas, no hacerlo así implica que la nueva clase derivada será también abstracta ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 108 Clases abstractas P R O G R A M A C I Ó N Ejemplo: class Persona { public: Persona(char *n) { strcpy(nombre, n); } virtual void Mostrar() = 0; protected: char nombre[30]; }; class Empleado : public Persona { public: Empleado(char *n, int s) : Persona(n), salario(s) {} void Mostrar() { cout << "Empleado: " << nombre << ", Salario: " << salario << endl; } protected: int salario; }; Persona *Jose = new Persona(“Jose”); // ERROR Persona *Pepito = new Empleado(“Pepito", 1000); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 109 Interfaces P R O G R A M A C I Ó N Las interfaces surgen como una evolución de la POO Programación orientada a componentes ante la necesidad de reutilizar y agrupar las distintas funcionalidades de un objeto en subconjuntos mas manejables Definen un cierto comportamiento o cualidades En términos de C++ es una clase abstracta con métodos virtuales puros La derivación múltiple nos permitirá luego agrupar varias de esas funcionalidades dentro de una clase nuestro objeto ira cobrando forma a partir de la herencia de distintas interfaces o cualidades ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 110 Interfaces P R O G R A M A C I Ó N Ejemplo: /* Interface para objetos dibujables */ class IDrawable { public: Virtual bool IsVisible()=0; virtual void Draw()=0; }; /* Interface para objetos actualizables */ class IUpdateable { public: virtual void Update(float dt)=0; }; Class Actor : public IUpdateable, public IDrawable { Public: bool IsVisible() { return true } void Draw() { ... } void Update (float dt) { ... } } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 111 Derivación múltiple P R O G R A M A C I Ó N C++ permite crear clases derivadas a partir de varias clases base Los objetos heredarán los datos y funciones de todas las clases base Al construir el nuevo objeto, si es necesario debemos llamar a los constructores de todas las clases base ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 112 Derivación múltiple P R O G R A M A C I Ó N Ejemplo: class ClaseA { public: ClaseA(int va = 10) : valorA(va) {} int LeerValor() const { return valorA; } protected: int valorA; }; class ClaseB { Public: ClaseB(int vb = 20) : valorB(vb) {} int LeerValor() const { return valorB; } protected: int valorB; }; class ClaseC : public ClaseA, public ClaseB { public: ClaseC(int va, int vb) : ClaseA(va), ClaseB(vb) {}; int LeerValorA() const { return ClaseA::LeerValor(); } int LeerValorB() const { return ClaseB::LeerValor(); } }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 113 Derivación múltiple P R O G R A M A C I Ó N Problema: Supongamos que tenemos una estructura de clases La ClaseD heredará dos veces los datos y funciones de la ClaseA, con la consiguiente ambigüedad a la hora de acceder a datos o funciones heredadas de ClaseA ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 114 Derivación múltiple P R O G R A M A C I Ó N Para solucionar esto se usan las clases virtuales class ClaseB : virtual public ClaseA {}; class ClaseC : virtual public ClaseA {}; class ClaseD : public ClaseB, public ClaseC {}; Desde el punto de vista de la ClaseB o ClaseC, no hay ninguna diferencia entre ésta declaración y la que hemos usado hasta ahora Sin embargo, ahora la ClaseD sólo heredará una vez la ClaseA ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 115 P R O G R A M A C I Ó N Example 08 –Shapes Jugando con la herencia y polimorfismo ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 116 Plantillas P R O G R A M A C I Ó N class TablaInt { public: TablaInt(int nElem); ~TablaInt(); int& operator[](int indice) { return pInt[indice]; } ... private: int *pInt; int nElementos; }; // Definición: TablaInt::TablaInt(int nElem) : nElementos(nElem) { pInt = new int[nElementos]; } TablaInt::~TablaInt() { delete[] pInt; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 117 Plantillas P R O G R A M A C I Ó N Según va aumentando la complejidad de nuestros programas descubrimos que tenemos que repetir una y otra vez las mismas estructuras A menudo tendremos que implementar arrays dinámicos para diferentes tipos de objetos, o listas dinámicas, pilas, colas, árboles, etc. El código es similar siempre, pero estamos obligados a rescribir ciertas funciones que dependen del tipo o de la clase del objeto que se almacena Las plantillas (templates) nos permiten parametrizar estas clases para adaptarlas a cualquier tipo de dato ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 118 Plantillas P R O G R A M A C I Ó N Ejemplo: plantillas de clases template <class T> class Tabla { public: Tabla(int nElem); ~Tabla(); T& operator[](int indice) { return pT[indice]; } private: T *pT; int nElementos; }; // Definición: template <class T> Tabla<T>::Tabla(int nElem) : nElementos(nElem) { pT = new T[nElementos]; } template <class T> Tabla<T>::~Tabla() { delete[] pT; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 119 Plantillas P R O G R A M A C I Ó N Ya sólo nos queda saber cómo declarar tablas del tipo que queramos Tabla<int> tablaInt(32); // Tabla de 32 enteros Tabla<float> tablaFloat(12); // Tabla de 12 floats Tabla<bool> tablaBool(10); // Tabla de 10 bools ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 120 Plantillas P R O G R A M A C I Ó N Ejemplo: plantillas de funciones template <class T> T max(T x, T y) { return (x > y) ? x : y; }; De esta forma tendremos definida la función max para cualquier tipo de dato que tenga implementado correctamente el operador “mayor que” ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 121 Plantillas P R O G R A M A C I Ó N Es posible crear funciones que admitan parámetros que sean una plantilla Hay dos modos de pasar las plantillas: se puede pasar una instancia determinada de la plantilla la plantilla genérica ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 122 Plantillas P R O G R A M A C I Ó N Ejemplo: paso de una instancia determinada void Incrementa(Tabla<int> &t); ... void Incrementa(Tabla<int> &t) { for(int i = 0; i < t.NElementos(); i++) t[i]++; } Tabla<int> TablaInt(5); Tabla<char> TablaChar(20); Incrementa(TablaInt); Incrementa(TablaChar); // ERROR ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 123 Plantillas P R O G R A M A C I Ó N Ejemplo: paso de la plantilla genérica template<class T> void Mostrar(Tabla<T> &t); ... template<class T> void Mostrar(Tabla<T> &t) { // (4) for(int i = 0; i < t.NElementos(); i++) cout << t[i] << endl; } Tabla<int> TablaInt(5); Tabla<char> TablaChar(20); Mostrar(TablaInt); Mostrar(TablaCadena); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 124 Plantillas P R O G R A M A C I Ó N Amigos de plantillas template <class T> class Tabla { ... friend void Mostrar<>(Tabla<T>&); ... }; template<class T> class Tabla { ... friend void Mostrar<>(Tabla<int>&); ... }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 125 Librería estándar de C++ P R O G R A M A C I Ó N El ANSI de C++ define ciertas librerías de plantillas conocidas como STL (Standard Template Library) Contiene muchas definiciones de plantillas para crear contenedores como listas, colas, pilas, árboles, tablas HASH, mapas, etc. Además proporciona algoritmos que permiten manipular fácilmente estos contenedores La STL introduce igualmente el concepto de iterador que permite recorrer fácilmente un contenedor sin tener en cuenta la manera en que ha sido implementado ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 126 P R O G R A M A C I Ó N Example 09 - Plantilla de una pila ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 127 Excepciones P R O G R A M A C I Ó N C++ proporciona un mecanismo más potente para detectar errores de ejecución: las excepciones Si uno de esos errores se produce y no implementamos el manejo de excepciones, el programa sencillamente terminará abruptamente Para ello disponemos de tres palabras reservadas extra: try, catch y throw ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 128 Excepciones P R O G R A M A C I Ó N Ejemplo: manejo de excepciones #include <iostream> using namespace std; int main() { int *x; int y = 100000000; try { x = new int[y]; x[0] = 10; cout << "Puntero: " << (void *) x << endl; delete[] x; } catch(std::bad_alloc&) { cout << "Memoria insuficiente" << endl; } cin.get(); return 0; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 129 Excepciones P R O G R A M A C I Ó N Manejo de excepciones La manipulación de excepciones consiste en transferir la ejecución del programa desde el punto donde se produce la excepción a un manipulador que coincida con el motivo de la excepción Un manipulador consiste en un bloque "try", donde se incluye el código que puede producir la excepción A continuación encontraremos uno o varios bloques "catch", y entre paréntesis una referencia o un objeto. Estos bloques contienen el código necesario para tratar una excepción de un tipo concreto En el caso del operador "new", si se produce una excepción, se hace un "throw" de un objeto de la clase "std::bad_alloc" ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 130 Excepciones P R O G R A M A C I Ó N Captura de excepciones Una excepción se puede producir por un "throw" que se encuentre dentro del bloque "try" asociado, o en una de las funciones llamadas desde él Cuando se produce una excepción se busca un manipulador apropiado en el rango del "try" actual Si no se encuentra se retrocede al anterior, de modo recursivo, hasta encontrarlo Cuando se encuentra se destruyen todos los objetos locales en todos los niveles por los que hemos pasado ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 131 Excepciones P R O G R A M A C I Ó N Ejemplo: propagación de excepciones int main() { try { try { try { throw 'x'; // valor de tipo char } catch(int i) {} catch(float k) {} } catch(unsigned int x) {} } catch(char c) { cout << "El valor de c es: " << c << endl; } cin.get(); return 0; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 132 Excepciones P R O G R A M A C I Ó N Si no se encontrase ningún "catch" adecuado, se abandona el programa, del mismo modo que si se produce una excepción y no hemos hecho ningún tipo de manipulación de excepciones Para evitar eso existe un "catch" general, que captura cualquier "throw" para el que no exista un "catch" catch(...) { cout << "Excepción imprevista" << endl; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 133 Excepciones P R O G R A M A C I Ó N La clase exception Existe una clase base "exception" de la que podemos heredar nuestras propias clases derivadas para pasar objetos a los manipuladores Aplicando polimorfismo necesitamos un único "catch" para procesar todas las posibles excepciones class exception { public: exception() throw() { } virtual ~exception() throw(); virtual const char* what() const throw(); }; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 134 Excepciones P R O G R A M A C I Ó N Ejemplo: custom exception class customException : public exception { public: customException(int mot) : exception(), motivo(mot) {} const char* what() const throw(); private: int motivo; }; const char* customException::what() const throw() { switch(motivo) { case 1: return "Fichero de origen no existe"; case 2: return "No es posible abrir el fichero de salida"; } return "Error inesperado"; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 135 Excepciones P R O G R A M A C I Ó N Orden en la captura de excepciones Cuando se derivan clases desde la clase base "exception" hay que tener cuidado en el orden en que las capturamos Debido que se aplica polimorfismo, cualquier objeto de la jerarquía se ajustará al catch que tenga por argumento un objeto o referencia de la clase base ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 136 Excepciones P R O G R A M A C I Ó N Ejemplo: orden en captura excepciones class Excep2 : public exception {} class Excep3 :public Excep2 {} ... try { // Nuestro código } catch(Excep2&) { // tratamiento } catch(Excep3&) { // tratamiento } catch(exception&) { // tratamiento } catch(...) { // tratamiento } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 137 Excepciones P R O G R A M A C I Ó N Especificaciones de excepciones Se puede añadir una especificación de las posibles excepciones que puede producir una función De este modo indicamos que la función sólo puede hacer un "throw" de uno de los tipos especificados en la lista El compilador no verifica si realmente es así, sólo se verifica durante la ejecución, de modo que si se produce una excepción no permitida, el programa termina int Compara(int, int) throw(); int CrearArray(int) throw(std::bad_alloc); int MiFuncion(char *) throw(std::bad_alloc, ExDivCero); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 138 Excepciones P R O G R A M A C I Ó N Excepciones en destructores Está desaconsejado que los destructores puedan producir excepciones Los destructores pueden ser invocados automáticamente cuando se procesa una excepción, y si durante ese proceso se produce de nuevo una excepción, el programa terminará inmediatamente La mejor solución es procesar las excepciones dentro del destructor si es necesario ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 139 Excepciones P R O G R A M A C I Ó N Ejemplo: excepciones en destructores Miclase::~MiClase() throw () { try { // Necesitamos copiar un fichero cuando se // destruya un objeto de esta clase, pero // CopiaFichero puede generar una excepción CopiaFichero("actual.log", "viejo.log"); } catch(CopiaEx&) { cout << "No se pudo copiar el fichero 'actual.log‘” << endl; } } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 140 Excepciones P R O G R A M A C I Ó N Relanzar una excepción Podemos lanzar una excepción a través de los siguientes niveles, aunque la hayamos capturado A eso se le llama relanzarla, y para ello se usa "throw;", sin argumentos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 141 Excepciones P R O G R A M A C I Ó N Ejemplo: relanzar una excepción try { // Programa Programa(); } catch(int x) { cout << "Excepción relanzada capturada." << endl; cout << "error: " << x << endl; } void Programa() { try { // Operaciones... throw 10; } catch(int x) { // Relanzar, no nos interesa manejar aquí throw; } } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 142 P R O G R A M A C I Ó N Operadores de cambio de tipo en C++ ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 143 Castings en C++ P R O G R A M A C I Ó N Hasta ahora hemos usado sólo el casting que existe en C, pero su uso está desaconsejado Se recomienda usar uno de los nuevos operadores de C++ diseñados para realizar esta tarea C++ dispone de cuatro operadores para realizar castings: Operador static_cast<> Operador const_cast<> Operador reinterpret_cast<> Operador dynamic_cast<> ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 144 Castings en C++ P R O G R A M A C I Ó N Operador static_cast<> Este operador se usa para realizar conversiones de tipo que de otro modo haría el compilador automáticamente por ejemplo, convertir un puntero a un objeto de una clase derivada a un puntero a una clase base pública Otro ejemplo, en lugar de usar el operador de conversión de forma implícita, podemos usarlo mediante el operador static_cast Este operador se usa con objeto de aclarar el código pBase = static_cast<Base *> (pDerivada); Tiempo Ahora(12,24); int minutos = static_cast<int> (Ahora); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 145 Castings en C++ P R O G R A M A C I Ó N Operador const_cast<> Se usa para eliminar o añadir los modificadores const y volatile de una expresión La conversión tiene que ser del mismo tipo, salvo por los modificadores const o volatile que tengan que aparecer o desaparecer const int x = 10; int *x_var; x_var = const_cast<int*> (&x); // Válido // x_var = &x; // Ilegal, el compilador da error *x_var = 14; // Indefinido ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 146 Castings en C++ P R O G R A M A C I Ó N Operador reinterpret_cast<> Se usa para hacer cambios de tipo a nivel de bits, es decir, el valor de la expresión a convertir se interpreta como si fuese un objeto del tipo deseado Este tipo de conversión es peligrosa struct tipoRegistro { char nombre[32]; int edad; float altura; }; ifstream fentrada("prueba.dat", ios::in | ios::binary); fentrada.read(reinterpret_cast<char *> &pepe2, sizeof(tipoRegistro)); fentrada.close(); ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 147 Castings en C++ P R O G R A M A C I Ó N Operador dynamic_cast<> Este operador sólo puede usarse con objetos polimórficos, cualquier intento de aplicarlo a objetos de tipos fundamentales o agregados o de clases no polimórficas dará como resultado un error Lo que el programa intentará hacer, durante la ejecución, es obtener un puntero o una referencia a un objeto de cierta una base en forma de clase derivada pero puede que se consiga, o puede que no ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 148 Castings en C++ P R O G R A M A C I Ó N Operador dynamic_cast<> Con punteros: void VerSueldo(Persona *p) { if(Empleado *pEmp = dynamic_cast<Empleado *> (p)) pEmp->VerSueldo(); else cout << "No tiene salario." << endl; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 149 Castings en C++ P R O G R A M A C I Ó N Operador dynamic_cast<> Con referencias: void VerSueldo(Persona &p) { Empleado& rEmp = dynamic_cast<Empleado &> p; ... } Al aplicar el operador con referencias hay que tener más cuidado, ¿Qué pasará si el casting falla? ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 150 P R O G R A M A C I Ó N Ficheros en C++ ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 151 Ficheros en C++ P R O G R A M A C I Ó N Usar streams facilita mucho el acceso a ficheros en disco veremos que una vez que creemos un stream para un fichero, podremos trabajar con él igual que lo hacemos con cin o cout Mediante las clases ofstream, ifstream y fstream tendremos acceso a gran cantidad de funciones que nos van a facilitar la tarea ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 152 Ficheros en C++ P R O G R A M A C I Ó N #include <iostream> #include <fstream> using namespace std; int main() { char cadena[128]; // Crea un fichero de salida ofstream fs("nombre.txt"); fs << "Hola, mundo" << endl; fs.close(); // Abre un fichero de entrada ifstream fe("nombre.txt"); // Leeremos mediante getline, si lo hiciéramos mediante el operador >> sólo leeríamos parte de la cadena: fe.getline(cadena, 128); cout << cadena << endl; return 0; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 153 Ficheros en C++ P R O G R A M A C I Ó N Muchos sistemas operativos distinguen ficheros de texto y ficheros binarios entre En general, usaremos ficheros de texto para almacenar información que pueda o deba ser manipulada con un editor de texto Ficheros binarios para todo lo demás Un fichero binario permite almacenar estructuras completas, en las que se mezclen datos de cadenas con datos numéricos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 154 Ficheros en C++ P R O G R A M A C I Ó N struct tipoRegistro { char nombre[32]; int edad; float altura; }; int main() { tipoRegistro pepe, pepe2; ofstream fsalida("prueba.dat", ios::out | ios::binary); fsalida.write(reinterpret_cast<char *> &pepe, sizeof(tipoRegistro)); fsalida.close(); ifstream fentrada("prueba.dat", ios::in | ios::binary); fentrada.read(reinterpret_cast<char *> &pepe2, sizeof(tipoRegistro)); fentrada.close(); return 0; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 155 Ficheros en C++ P R O G R A M A C I Ó N Ficheros de acceso aleatorio Otra característica importante de los ficheros es la posibilidad de trabajar con ellos haciendo acceso aleatorio, es decir, poder hacer lecturas o escrituras en cualquier punto del fichero Para eso disponemos de las funciones seekp y seekg, que permiten cambiar la posición del fichero en la que se hará la siguiente escritura o lectura ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 156 Ficheros en C++ P R O G R A M A C I Ó N char cad[20]; char mes[][20] = {"Enero", "Febrero", "Marzo", ...}; // Acceso aleatorio for(i = 11; i >= 0; i--) { fentrada.seekg(20 * i, ios::beg); fentrada.read(cad, 20); cout << cad << endl; } /* Calcular el número de elementos almacenados en un fichero: */ // ir al final del fichero fentrada.seekg(0, ios::end); // leer la posición actual pos = fentrada.tellg(); // El número de registros es el tamaño en bytes dividido entre el tamaño del registro cout << “Número de registros: " << pos/20 << endl; ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 157 Ficheros en C++ P R O G R A M A C I Ó N Sobrecarga de operadores << y >> Una de las principales ventajas de trabajar con streams es que nos permiten sobrecargar los operadores << y >> para realizar salidas y entradas de nuestros propios tipos de datos ostream& operator<<(ostream &os, Registro& reg) { os << "Nombre: " << reg.LeeNombre() <<"\nEdad: " << reg.LeeEdad() << "\nTelefono: " << reg.LeeTelefono(); return os; } ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 158 Ficheros en C++ P R O G R A M A C I Ó N Example 10 - Importación de modelos 3D Lectura de ficheros de texto mediante streams ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 159 Libros recomendados P R O G R A M A C I Ó N ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 160 P R O G R A M A C I Ó N Curso 0: Programación orientada a objetos (POO) Iván Alduán ([email protected]) (despacho 143 Departamental II, Campus Móstoles) ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA 161
© Copyright 2024