Manual Refer en CIA c++

March 23, 2018 | Author: manuel_urbano_3 | Category: C++, Bit, Quotation Mark, Control Flow, Software Development


Comments



Description

´ UNIVERSIDAD DE MALAGA Dpt. Lenguajes y CC. Computaci´n o E.T.S.I.Inform´tica a Ingenier´ Inform´tica ıa a Programaci´n Elemental en C++ o Manual de Referencia Abreviado Revision : 1,21 2 Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a ´ Indice general Pr´logo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o 1. Un programa C++ 2. Tipos simples 2.1. Declaraci´n vs. definici´n . . . . . . . . . . o o 2.2. Tipos simples predefinidos . . . . . . . . . . 2.3. Tipos simples enumerados . . . . . . . . . . 2.4. Constantes y variables . . . . . . . . . . . . 2.5. Operadores . . . . . . . . . . . . . . . . . . 2.6. Conversiones autom´ticas de tipos . . . . . a 2.6.1. Promociones . . . . . . . . . . . . . 2.6.2. Conversiones enteras . . . . . . . . . 2.6.3. Conversiones aritm´ticas habituales e 2.7. Conversiones expl´ ıcitas de tipos . . . . . . . 3. Estructuras de control 3.1. Sentencia, secuencia y bloque . 3.2. Declaraciones globales y locales 3.3. Sentencias de asignaci´n . . . . o 3.4. Sentencias de Selecci´n . . . . . o 3.5. Sentencias de Iteraci´n. Bucles o 7 9 11 11 11 12 13 14 15 15 15 15 16 19 19 19 20 21 22 25 25 26 26 27 28 31 31 31 35 35 35 36 37 38 39 39 40 41 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. Subprogramas. Funciones y procedimientos 4.1. Funciones y procedimientos . . . . . . . . . . 4.2. Definici´n de subprogramas . . . . . . . . . . o 4.3. Par´metros por valor y por referencia . . . . a 4.4. Subprogramas “en l´ ınea” . . . . . . . . . . . . 4.5. Declaraci´n de subprogramas . . . . . . . . . o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. Entrada / Salida b´sica a 5.1. Salida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2. Entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6. Tipos compuestos 6.1. Registros o estructuras . . . . . . . . . . . . . 6.2. Agregados o “Arrays” . . . . . . . . . . . . . 6.3. Agregados multidimensionales . . . . . . . . . 6.4. Agregados o “Arrays” de la biblioteca . . . . 6.5. Agregados multidimensionales . . . . . . . . . 6.6. Cadenas de caracteres . . . . . . . . . . . . . 6.7. Par´metros de tipos compuestos . . . . . . . a 6.8. Par´metros de agregados de tama˜o variable a n 6.9. Inicializaci´n de variables de tipo compuesto o 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Flujo de salida a una cadena . . . . . . . . . . . . . . . . . . . . . . .7. . Operaciones sobre variables de tipo puntero . . . 9.2. . . . .12. . . .1. . .Tipos abstractos de datos 13. . . . . . . . . . . . . . . .11. . . . .7. . . . . . . . . . .9. . . . . .10. . 41 41 42 43 47 47 47 48 48 49 49 50 50 50 53 53 53 54 55 56 57 58 60 60 61 61 62 62 63 63 65 65 66 69 69 69 70 71 73 73 74 77 87 88 88 91 95 Universidad de M´laga a 7. . . . . . . . . .5. . . . . . . . . . . . . . 9. 9. . . . . . . . . . . . . . . . . . . . Operaciones de entrada . . . . . . . Sobrecarga de operadores . . . . M´todos definidos autom´ticamente por el compilador . . . . . . . . . . . . . . Campos de bits . . . . Uniones . 12. . 14. . . . . . . . . . . . . . . . . . . . . . . . . Ampliaci´n. . . . . . . . . . . . . . . . . . . . . . Punteros a 8. . Ejemplo de ficheros . . . . . . . . . . . . . . . . . . . Los flujos est´ndares . . . . . Declaraci´n . . .11. . . . . . . . . . . . .2. . . . o 8. . . . .9. . . . .1. . . . . . . . . . . . . Requisitos de las clases respecto a las excepciones . . 6. . . Estado . .2. . . . . . . . Memoria din´mica de agregados . . .12. . . . . . . . . . . . . . . . . . . . 8. . . . . . . . . . . . . Paso de par´metros de variables de tipo puntero a 8. . . . . . . . . .14. . . . . .8. . . . . . . . . . . . . . 11. . . . . . . . . . . . . . . . . . . . . . Operador de indirecci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ficheros . . . . . . . . . . . . . Lenguajes y Ciencias de la Computaci´n o . . . . . . . . . . . . . . . . . . . Plantillas o e 15. . . . . . . . . . . . . . . 13. . 9. . . . . . . . . . . . . . . . . . . . . Biblioteca “string” de C++ 8. . Entrada / Salida. . 9. . . . . . . . .2. . . . . . . Ejemplos . . . 10. . . . . . . . . .2. . . . . . . . . . . . . . . . . . . . . El “buffer” de entrada y el “buffer” de salida . . . . .3. . . . . . . . Asertos . . . . . . . . . .M´dulos o 10. . a 8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ficheros de salida . . . . . . . 11. o 8. . . . . . . Operaciones de salida . . .1. Control de flujos. . 9. . . . . . . . . . . a . . . . . . . . . . . . . . . . . . . . . . . Jerarqu´ de clases de flujo est´ndar . . . . . . . . . . .4. . . . . . . . . . .6. . . . . . . . . . Punteros a subprogramas . . . 9. . . . Ficheros de entrada/salida . . Buffer . . . . 9. . . . . . . . . . . . 9.3. . . . . . . . . . . .15. . . . . . . . . . . . . . . . . . . . . . . . . Espacios de nombre . . . Ficheros de entrada . . . . . . . . . . . . . . . Memoria Din´mica . . . . . . . . .Programaci´n Gen´rica. . . . . . . . . . . . . . . . . . . . 9. . .1. . ıa a . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8.Programaci´n orientada a objetos o Dpto. . . . . . Memoria din´mica. . . . . . . . 6. .5. . . . . . . . . . . . Excepciones 11. . . . . . Operaciones sobre variables de tipo compuesto . . . . . . . . .6.3. . . . . . . . . . . . . . o 8. . . .2. . . . . . . . . . . . . . . Definici´n e implementaci´n . . 8. . . . . . . . . . . . . . . . . . . . . . . . . . Flujo de entrada desde una cadena . . . . . . . . .Sobrecarga de subprogramas y operadores 12. . . . . . . . . . . . . . . . Excepciones est´ndares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12. . . . . . . Sobrecarga de subprogramas . . . . . . . a 9. . . . . . . 13. . . . . . . . . . . . . . . . . . . . . . . . Estructuras autoreferenciadas . . . . . . . . . . . . . . . . . . . . . . . . . . e a 13.4 ´ INDICE GENERAL 6. . . . . . .13. . control y ficheros o 9. . . . . . . . .3. . . . . . . . . . . . . . . . . . a 8. . . . . 11. . . Excepciones . . . . . . .1. . . . . . . . . . . . . . . 9. . . . . . . . . . . . . . . . . . . . . . . . o o 10. . . . . . . . . . . . . Entrada/Salida formateada . . . . . . . . Punteros a miembros . . . . . . . . . Desreferenciaci´n . . . . . . . . 11.4. . . . . . . . . . 9. . .1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9. . . .10. . . . . . 9.Manejo de errores. . . . . . . . . . . . . . . . . 16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . O 16. . . . . . . . . . . . 143 o a Dpto. . . . . . . ultiset .17. . . . . . . Contenedores . . . . . . . R 5 99 99 99 99 100 100 100 100 101 101 101 101 101 102 102 102 102 104 107 108 109 110 110 111 112 112 113 114 114 115 116 116 119 120 122 124 125 126 126 127 127 127 128 129 130 131 134 138 140 140 . . e 17. . . . . . . . . . . . . . . . . . O o 16. . . . . . 16. . . . . . . . . . . o 17. .11. . . . . . . . . . . . . . . . . . . . .1. 17. . .5. . . s 16. . . . . .15. . . . . . . . . . . . . . . . . . . . A 16. . Operaciones de Pila y Cola . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . .1.1.8. . . . 17. . . . . . . . . . . . 16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .´ INDICE GENERAL 16. . . . . . . . . . . . . . . . . . . . . .Resumen . . . . . . . . . . . . . . . . . . . i 16. . . . . . . . . . . . . . 16.9. . . . . . . . . . . . . . . .13. . . . . . . b 16. . . . . . . . . . . . . . . . . . . . . . 16. 17. . . . . . . . list . .6. . .23. . . Ocultar la implementaci´n . . . . . . i 16. .1. . . . . . . . . . . . . . . 16. . . . . . . . . . . . . . . . . . . . . . . .1. . .1. . . . . . . . . 16. .13.1. . . . . . . . . . . . . . . . . .3. . . . .18. . . . . . . . . . . . . . .1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o o 17. . . . . . . . .nversos . . . .2. . . . . . . . . . . . stack .2. . . . . . . . .1. . . . . . . . . Adquisici´n de recursos es Inicializaci´n . . . . . . . . . . bjetos Funci´n y Predicados . . . . . . . Iteradores . . . . . irectos . . . .21. . . . . . . . . . . . .T´cnicas de programaci´n usuales en C++ e o 17. . . . . . . . . 16. . . . . . . . 16. . . . . . 16. .20. . . . . . . . . . . . . . 16.16. . . . . . . . RAII gen´rico . . . . . . . . . . . . . . 16. . . . . . . . . . . . . . . . . . . sobre contenedores . . . . . . . . .7. .14. . . .1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . .6. . . . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . itset . . . . . . . . . . . . . . . . . . . . . . . . . . .Biblioteca Est´ndar de C++. . . vector . 16. . . . Caracter´ ısticas comunes . .1. . . . RAII simple de memoria din´mica . . . . . . . . . . . . . . . . . . . . ´ Lımites . . . . . . . . queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Operaciones de Lista . . . . . . . . . . . . . . . . . . . . . . 16. . . . . . . . . . . . .1. . . . .6. . . . . . lgoritmos . . RAII simple gen´rico . . . . . . . d 16. . . . . . . . . . . . . ultimap . . . . . . . . . . .5. . . . . . . . . . 16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2. . . et . . . . . . . . . . . . . .1. tream iterators . . . .1. teradores .7. deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipos definidos . . . . . . . . . . . . . Gesti´n de Memoria Din´mica . . . string .25. . . . . . . . . o 16. . . . . . . . . . . . 16. . 16. . . . . . . . . . . . Operaciones . . . . . . . . . . . . . . priority-queue . . . . . . . . . . . . . . . . . . . e 17. . . . . . . . . . . . . . . . . . m 16. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Redirecci´n transparente de la salida est´ndar o a 17. . . . . . . . .Asignaci´n . . . . . . .1. . . . . . . . . . . . . . . map . . . . . Eventos . . . . Restricciones en programaci´n gen´rica . . . . . . . . . 18. . . . . . . . . . . . . . . . . . .1.22. . . . . . . . . . . . . . . . . . . Acceso . . . . . . . .Operaciones sobre Iteradores . . . . . . . . . . . . .4. . .19. . .Gesti´n Din´mica de Memoria o a 143 18. . peraciones sobre Iteradores . a 17. . . .3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . arant´ (excepciones) de operaciones G ıas 16. . . . . 16. . . . . . . . . . . . . . . . . . . umericos . . . . . . . . . . . . .11. . . . . . . . . . . . . . . . . . . . . m 16. . 16. . . . . . . . . . . .1. . . . . . . . . . . . .1. . . . . . . . . 16. . 16. . . . . . . . . . . .12. . . . .10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1.24. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . s 16. . . . . . . Constructores . . . . . . . o e . . . . . . . . . .1. . . . . . .1. . .9. . . . . . . . . . un Time Type Information (RTTI) . . . . . . . . . . . . . . . . . .nserters . . . . . .3. . . . . . N 16. .3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . auto ptr (unique ptr) . . . . .10. . 16. . . . . . . . . 17. . . . Contenedores . . . . . . . . . . . . . . . . . .2. . . .Operaciones Asociativas .8. . . . . . . Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . . . . . . I 16. . Control de elementos de un contenedor . . . a un . . . . . . . . . . . . . . . . . . . . . . . . . . . . STL a 16. . . . . . . . . . . . .1. . . . . . . . . . . . . .5. . . . . Ficheros . . . . . . . . . .12. . . . . . . . . . . . . . . . . . . . . . . cstdio . . . . conio) . . . . . Bibliograf´ ıa ´ Indice ANSI-C (+ . . . . . . . .6 A. . . . . . . . cmath . .8. . . . . . . . . . . . . .3. . . . . . . . cstdlib . . . . . . . . . C. . . . . cctype . . . . . Precedencia de Operadores en C B. cstring . . . . . . . . . . . .h . . . . . . . . . cfloat . . . . . . . . . . . . . . . . . . . . . . . . . . . Precedencia de Operadores en C++ C.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C. . . . . . . . . . .7. . . . . . . . . . . . . . . El preprocesador E. . . . Biblioteca b´sica a C. . . . . . . . . Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . . . . . . . . . . . cassert .10. . . . Caracter´ ısticas no contempladas G. . . . . . . . . . . . . . C. . . . . . . . . . . . . . . . . . . . . .6. . . . . . . . . . . . . . . Dpto. . . . . . . . . . . . . .conio. . . . . . . . . . . . . . . Errores m´s comunes a F. . . . . . . . C. . . . . . . . . . . . . . . . . . . . . . . C. . . ctime . . . . . . . . . . . . . . . . . climits . . .1. . . . C. . . . . . . . . . .2. C. . . . . . . . . .5. . . . C. . . . . . . . . C. . . D. . . . . . . . . . . . ´ INDICE GENERAL 149 151 155 155 155 156 156 157 157 158 158 158 158 161 163 165 167 167 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . restringiremos tanto las estructuras a utilizar como la forma de utilizarlas. si se o a utiliza sin rigor puede dar lugar a construcciones y estructuras de programaci´n complejas. a´n siendo una versi´n preliminar. dada la amplitud ıa o a del lenguaje. No pretende ser una gu´ extensa del lenguaje de programaci´n C++. hay caracter´ ısticas del mismo que no han sido contempladas por exceder lo que entendemos que es un curso de programaci´n elemental. dif´ o ıciles de comprender y propensas a errores. Est´ orientada a alumnos de primer curso de programaci´n a o de Ingenier´ Inform´tica. o Este manual ha sido elaborado en el Dpto. Se difunde en o la creencia de que puede ser util. Adem´s. a Es una versi´n preliminar y se encuentra actualmente bajo desarrollo. ıa a No pretende “ense˜ar a programar”. de Lenguajes y Ciencias de la Computaci´n de la o Universidad de M´laga. Debido a ello. y simplemente muestra como aplicarlos utilizando el Lenguaje de o Programaci´n C++ o El lenguaje de programaci´n C++ es un lenguaje muy flexible y vers´til.Pr´logo o Este manual pretende ser una gu´ de referencia abreviada para la utilizaci´n del lenguaje ıa o C++ en el desarrollo de programas. y debido a ello. supone que el lector posee los fundamentos necesarios n relativos a la programaci´n. ´ u o 7 . Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .8 ´ INDICE GENERAL Dpto. debe definirse una funci´n principal. Posteriormente.Cap´ ıtulo 1 Un programa C++ En principio. 10). /* * Imprime los numeros menores a ’n’ */ void numeros(int n) { for (int i = 0. o que indica donde comienza la ejecuci´n del programa. // escribe el valor de ’i’ } cout << endl. de constantes (vease cap´ ıtulo 2) y de subprogramas (cap. u o En caso de no aparecer expl´ ıcitamente el valor de retorno de main. Al finalizar. el sistema recibir´ por a defecto un valor indicando terminaci´n normal.cpp”. dicha funci´n devolver´ un o o a n´mero entero que indica al Sistema Operativo el estado de terminaci´n tr´s la ejecuci´n del u o a o programa (un n´mero 0 indica terminaci´n normal). llamada main. normalmente. i < n. “. etc. “. Dentro de este fichero.fichero: numeros. De entre las definiciones de subprogramas. } 9 . cin >> maximo. aparecer´n al principio unas l´ a ıneas para incluir las definiciones de los m´dulos de biblioteca que utilice nuestro programa. se realizar´n o a declaraciones y definiciones de tipos. 4) cuyo ´mbito de visibilidad ser´ global a todo el fichero (desde el punto donde ha sido declarado a a hasta el final del fichero). // return 0. ++i) { cout << i << " ". o Ejemplo de un programa que imprime los n´meros menores que uno dado por teclado. un programa C++ se almacena en un fichero cuya extensi´n ser´ una de las sio a guientes: “. M´s adelante consideraremos programas complejos cuyo c´digo a o se encuentra distribuido entre varios ficheros (cap.cpp -------------------------------------------#include <iostream> // biblioteca de entrada/salida using namespace std. numeros(maximo). // escribe ’salto de linea’ } int main() { int maximo. u //.cxx”. cout << "Introduce un numero: ".cc”. Campos de Registros: S´lo se utilizar´n letras min´sculas. Se construyen mediante una secuencia de letras y d´ ıgitos de cualquier longitud. funciones. media = suma / n. Tipos: Comenzar´n por una letra may´scula seguida por letras may´sculas. d´ o a u ıgitos y el caracter _. por lo que no deber´ a ıan utilizarse en programas. variables. d´ o a u ıgitos y el caracter _. u Variables: S´lo se utilizar´n letras min´sculas. u Delimitadores S´ ımbolos que indican comienzo o fin de una entidad. Funciones: S´lo se utilizar´n letras min´sculas. Comentarios y espacios en blanco Los comentarios en C++ se expresan de dos formas diferentes: Para comentarios cortos en l´ ınea con el c´digo de programa utilizaremos // que o indica comentario hasta el final de la l´ ınea. y s´lo pueden ser utilizadas con dicho sentido. constantes. min´sculas. o Identificadores Son nombres elegidos por el programador para representar entidades (tipos. tabuladores.10 CAP´ ITULO 1. los nombres que a comienzan con dicho car´cter se reservan para situaciones especiales. siendo el primer car´cter una letra. y podr´n ser num´ricos. caracteres a e y cadenas. retorno de carro. u u Dpto. Constantes literales Son valores que aparecen expl´ ıcitamente en el programa. Deber´ haber como m´ a ınimo una letra min´scula. // media de ’n’ numeros Para comentarios largos (de varias lineas) utilizaremos /* que indica comentario hasta */ /* * Ordena por el metodo quicksort * Recibe el array y el numero de elementos que contine * Devuelve el array ordenado */ Los espacios en blanco. d´ o a u ıgitos y el caracter _. etc) en el programa. las letras min´sculas se consideran diferentes de las may´sculas. Operadores S´ ımbolos con significado propio seg´n el contexto en el que se utilicen. a u u u digitos o _. UN PROGRAMA C++ //. nueva l´ ınea. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . seguiremos la siguiente convenci´n para los identificadores: o Constantes: S´lo se utilizar´n letras may´sculas.fin: numeros. sin embargo. excepto en el sentido en que separan componentes. avance de p´gina y los a comentarios son ignorados. En este manual.cpp ------------------------------------------------ En un programa C++ podemos distinguir los siguientes elementos b´sicos: a Palabras reservadas Son un conjunto de palabras que tienen un significado predeterminado para el compilador. d´ o a u ıgitos y el caracter _. Nota: en C++. El _ se considera como una letra. a Una definici´n “establece las caracter´ o ısticas” de una determinada entidad para el identificador al cual se refiere.Cap´ ıtulo 2 Tipos simples El tipo define las caracteristicas que tiene una determinada entidad. aunque puede haber varias ´ o declaraciones.1. control. no se puede acceder o modificar parte de ellos (aunque ´sto se pueda realizar mediante operaciones de bits) y los tipos compuestos se caracterizan e por estar formados como un agregado o composici´n de otros. o 2. especificando o su tipo. antes de que sean utilizados. de tal forma que toda entidad manipulada por un programa lleva asociado un determinado tipo. La interpretaci´n del valor almacenado. s´ ımbolos alfanum´ricos. Declaraci´n vs. El conjunto de operaciones/manipulaciones aplicables a la entidad. de e puntuaci´n. identificador. Las caracter´ ısticas que el tipo define son: El rango de posibles valores que la entidad puede tomar. Los tipos simples se caracterizan porque sus valores son indivisibles. es decir. Toda definici´n es a su vez tambi´n una declaraci´n. definici´n o o Con objeto de clarificar la terminolog´ en C++ una declaraci´n “presenta” un identificador ıa. Suele almacenarse en el tama˜o de palabra n mas peque˜o posible direccionable (normalmente 1 byte).2. 11 . espacios. ya sean simples o compuestos. Tipos simples predefinidos Los tipos simples predefinidos en C++ son: bool char int float double El tipo bool se utiliza para representar valores l´gicos o booleanos. solo exista una unica definici´n. 2. o para el cual la entidad a la que hace referencia deber´ ser definida posteriormente. Es obligatorio la declaraci´n de las entidades que se manipulen en el programa. es decir. los valores “Verdao dero” o “Falso” o las constantes logicas true y false. etc. valores. Los tipos se pueden clasificar en tipos simples y tipos compuestos. etc y normalmente utilizan un espacio de almacenamiento de 1 byte o (8 bits) y puede representar 256 posibles valores diferentes. o e o Es obligatorio que por cada entidad. n El tipo char se utiliza para representar los caracteres. o El espacio de almacenamiento necesario para almacenar dichos valores. es decir. a o A dicho tipo se le llama tipo enumerado y se define de la siguiente forma: enum Color { ROJO. se definir´ en base a una enumeraci´n de los posibles valores que pueda tomar la entidad asociada. Tanto el tipo float como el double se utilizan para representar n´meros reales en formato de u punto flotante diferenci´ndose en el rango de valores que representan. Marzo. Veamos un cuadro resumen con los tipos predefinidos. el programador puede definir nuevos tipos simples que definan mejor las caracter´ ısticas de las entidades manipuladas por el programa. Junio.3621e-4932 Max: 1. su espacio de almacenamiento y el rango de valores para una m´quina de 32 bits: a --------------------------------------------------------------------------bool: 1 bytes char: 1 bytes Min: -128 Max: 127 UMax: 255 short: 2 bytes Min: -32768 Max: 32767 UMax: 65535 int: 4 bytes Min: -2147483648 Max: 2147483647 UMax: 4294967295 long: 4 bytes Min: -2147483648 Max: 2147483647 UMax: 4294967295 float: 4 bytes Min: 1. El tipo double o tambien puede ser modificado con long para representar “cuadruple precisi´n” (normalmente 12 o bytes [96 bits]).79769e+308 long double: 12 bytes Min: 3.40282e+38 double:8 bytes Min: 2.17549e-38 Max: 3. Julio.3. Puede ser modificado para representar un rango de valores menor mediante el modificador short (normalmente 2 bytes [16 bits]) o para representar un rango de valores mayor mediante el modificador long (normalmente 4 bytes [32 bits]). Septiembre. AZUL. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Tambi´n puede ser modificado para representar solamente n´meros Naturales utie u lizando el modificador unsigned. utiliz´ndose el tipo double a a (normalmente 8 bytes [64 bits]) para representar n´meros de punto flotante en “doble precisi´n” y u o el tipo float (normalmente 4 bytes [32 bits]) para representar la “simple precisi´n”. Mayo. a Otro ejemplo de enumeraci´n: o enum Meses { Enero. De esta forma definimos el tipo Color. Abril. Dpto. Su representaci´n suele coincidir u o con la definida por el tama˜o de palabra del procesador sobre el que va a ser ejecutado. Febrero.18973e+4932 --------------------------------------------------------------------------- 2. Agosto. AMARILLO }. Tipos simples enumerados Ademas de los tipos simples predefinidos.22507e-308 Max: 1.12 CAP´ ITULO 2. TIPOS SIMPLES El tipo int se utiliza para representar los n´meros Enteros. As´ dicho tipo ı. hoy dia n normalmente es de 4 bytes (32 bits). que definir´ una entidad (constante o variable) que a podr´ tomar los diferentes valores enumerados. e Ejemplos de constantes literales: l´gicas (bool) o false. al primer valor se le asigna el a u cero. aquellas cuyo valor se asocia o a un identificador.. ’\t’. ’b’.’.. 2.. 13 Es posible asignar valores concretos a las enumeraciones. ’\35’. tienen tambi´n la propiedad de que cada posible valor tiene un e unico antecesor y un unico sucesor..25L Dpto. 5. Se les conoce tambi´n como tipos Escalares. ’:’.’. ’. true caracter char (s´ ımbolo entre comillas simples) ’a’. ’. 3.. ’\b’. -1520. Constantes y variables Podemos dividir las entidades que nuestro programa manipula en dos clases fundamentales: aquellos cuyo valor no var´ durante la ejecuci´n del programa (constantes) y aquellos otros cuyo ıa o valor puede ir cambiando durante la ejecuci´n del programa (variables). cout << ROJO << " " << AZUL << " " << AMARILLO << endl. . Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Diciembre }. .3456e-5.1415.54e-1F. ’1’. A ´stos se les conoce como tipos Ordinales”. ’9’. a trav´s del cual se representa. 50000UL..4. 0751 reales (punto flotante) 3. ’\r’..2. salvo los de e punto flotante (float y double). son aquellas cuyo valor aparece directamente en el programa. ´ ´ e 2.4. AMARILLO = 4 }. ’\n’. ’ ’. Aquellos valores que no se especifiquen ser´n consecutivos a los anteriores. Todos. AZUL..’. ’A’. ’z’. ’B’. ’0’. .. 0x10B3FC23.. Si no se especifica ning´n valor.. ’\a’. // 1 2 4 Todos los tipos simples tienen la propiedad de mantener una relaci´n de orden (se les puede o aplicar operadores relacionales).. o Las constantes pueden aparecer a su vez como constantes literales. y como constantes simb´licas. ’\x5F’. enum Color { ROJO = 1. ’Z’. ’. 30000L. Noviembre. cadenas de caracteres literales (caracteres entre comillas dobles) "Hola Pepe" "Hola\nJuan" "Hola " "Maria" enteros 123. -1e12. CONSTANTES Y VARIABLES Octubre.. . a dcha. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . int MAXIMO = 5000. asoc. Color COLOR_DEFECTO = ROJO. float total = 5. float N_E = 2. asoc.5. asoc. izq. a dcha. Significado de los operadores: Aritm´ticos e . Las variables se definen especificando su tipo e identificador con el que nos referiremos a ella.0. izq. asoc. izq. dcha. a dcha. asoc. a dcha. donde U.valor valor * valor / valor % valor + valor valor valor valor valor valor // // // // // // menos unario producto division (entera y real) modulo (resto) (no reales) suma resta Relacionales (resultado bool) Dpto. izq.7182F. short ELEMENTO = 1000. izq. a izq.141592. asoc. o Ejemplos de constantes simb´licas: o const const const const const const const const const const char CAMPANA = ’\a’. izq. B y T significan “operador unario”. a dcha. a dcha. unsigned long COLUMNAS = 200UL. a dcha. asoc. 2. a dcha. izq. izq. a dcha. long ULTIMO = 100000L. izq. Se les podr´ asignar un valor inicial en la definici´n. asoc. a dcha. dcha. double LOG10E = log(N_E). Operadores Para ver el tama˜o (en bytes) que ocupa un determinado tipo/entidad en memoria. unsigned FILAS = 200U.14 CAP´ ITULO 2. a izq. double N_PI = 3. el nombre simb´lico (o identificador) con el que nos referiremos a ella y el valor asociado tras el operador de o asignaci´n (=). podemos n aplicarle el siguiente operador: sizeof(tipo) Los siguientes operadores se pueden aplicar a los datos (ordenados por orden de precedencia): ! ~ * / % + << >> < <= > >= == != & ^ | && || ?: U B B B B B B B B B B T asoc. a o int contador = 0. y “operador ternario” respectivamente. asoc. asoc. TIPOS SIMPLES Las constantes se declaran indicando la palabra reservada const seguida por su tipo. asoc. “operador binario”. izq. el valor no cambia si se puede representar en el tipo destino.6. Conversiones autom´ticas de tipos a Es posible que nos interese realizar operaciones en las que se mezclen datos de tipos diferentes. C++ realiza conversiones de tipo autom´ticas (“castings”). el valor resultante simplemente tiene tantos bits del origen como quepan (descartando los de mayor orden). de tal forma que el resultado de la a operaci´n sea del tipo m´s amplio de los implicados en ella. desplazamiento de bits a la dch. viene definido por la implementaci´n. o 2.3. Si alg´n operando es de tipo long double. sino => valor2 2. negacion de bits (complemento) and de bits xor de bits or de bits L´gicos (s´lo booleanos) o o ! log log && log log || log // negacion logica // and logico // or logico Condicional log ? valor1 : valor2 // Si log es true => valor1. Siempre que sea posible. promocionan a unsigned int 2. CONVERSIONES AUTOMATICAS DE TIPOS valor valor valor valor valor valor < <= > >= == != valor valor valor valor valor valor // // // // // // comparacion comparacion comparacion comparacion comparacion comparacion menor menor o igual mayor mayor o igual igualdad desigualdad 15 Operadores de Bits (s´lo ordinales) o valor << despl valor >> despl ~ valor valor & valor valor ^ valor valor | valor // // // // // // desplazamiento de bits a la izq. o e se utiliza promoci´n a entero para crear int a partir de otros tipos mas cortos: o Si int puede representar todos los valores del tipo origen.6. promocionan a int En otro caso. u a) En otro caso. short. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .6. el otro se convierte a long double. si no.6. los valores se o a convierten de tal forma que no se pierda informaci´n: o 2.1. ushort }. valores de los siguientes tipos { char. u Dpto. Si el tipo destino es signed. uchar. Promociones Son conversiones impl´ ıcitas que preservan valores. Conversiones enteras Si el tipo destino es unsigned. Antes de realizar una operaci´n aritm´tica. Conversiones aritm´ticas habituales e Se realizan sobre los operandos de un operador binario para convertirlos a un tipo com´n u (resultado): 1.6. schar.´ 2. si alg´n operando es double el otro se convierte a double.2. 16 CAP´ ITULO 2. TIPOS SIMPLES b) En otro caso, si alg´n operando es float el otro se convierte a float. u c) En otro caso, se realizan promociones enteras sobre ambos operandos 2. En otro caso, si alg´n operando es de tipo unsigned long, el otro se convierte a unsigned long. u a) En otro caso, si alg´n operando es long int y el otro es unsigned int, si un long int u puede representar todos los valores de un unsigned int, el unsigned int se convierte a long int; en caso contrario, ambos se convierten a unsigned long int. b) En otro caso, si alg´n operando es long el otro se convierte a long. u c) En otro caso, si alg´n operando es unsigned el otro se convierte a unsigned. u d ) En otro caso, ambos operandos son int 2.7. Conversiones expl´ ıcitas de tipos Tambi´n es posible realizar conversiones de tipo expl´ e ıcitas. Para ello, se escribe el tipo al que queremos convertir y entre par´ntesis la expresi´n cuyo valor queremos convertir. Por ejemplo: e o int(’a’) int(ROJO) int(AMARILLO) Color(1) char(65) double(2) int(3.7) Color(c+1) // // // // // // // // convierte el caracter ’a’ a su valor entero (97) produce el entero 0 produce el entero 2 produce el Color AZUL produce el caracter ’A’ produce el real (doble precision) 2.0 produce en entero 3 si c es de tipo color, produce el siguiente valor de la enumeracion El tipo enumerado se convierte autom´ticamente a entero, aunque la conversi´n inversa no se a o realiza de forma autom´tica. As´ para incrementar una variable de tipo color se realizar´ de la a ı, a siguiente forma: enum Color { ROJO, AZUL, AMARILLO }; int main() { Color c = ROJO; c = Color(c + 1); // ahora c tiene el valor AMARILLO } Otra posibilidad de realizar conversiones expl´ ıcitas es mediante los siguientes operadores: int* p_int = static_cast<int*>(p_void); disp* ptr = reinterpret_cast<disp*>(0xff00); ave* ptr = dynamic_cast<ave*>(p_animal); ave& ref = dynamic_cast<ave&>(r_animal); char* ptr = const_cast<char*>(ptr_const_char) El operador static_cast<tipo>(valor) realiza conversiones entre tipos relacionados como un tipo puntero y otro tipo puntero de la misma jerarqu´ de clases, un enumerado ıa y un tipo integral, o un tipo en coma flotante y un tipo integral. Para un tipo primitivo, la conversi´n de tipos expresada de la siguiente forma: Tipo(valor) es equivalente a o static_cast<Tipo>(valor). El operador reinterpret_cast<tipo>(valor) trata las conversiones entre tipos no relacionados como un puntero y un entero, o un puntero y otro puntero no relacionado. Generalmente produce un valor del nuevo tipo que tiene el mismo patr´n de bits que su par´metro. Suelen o a corresponder a zonas de c´gigo no portable, y posiblemente problem´tica. o a Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a 2.7. CONVERSIONES EXPL´ ICITAS DE TIPOS 17 El operador dynamic_cast<tipo*>(ptr) comprueba en tiempo de ejecuci´n que ptr puede o ser convertido al tipo destino (utiliza informaci´n de tipos en tiempo de ejecuci´n RTTI). Si o o no puede ser convertido devuelve 0. Nota: ptr debe ser un puntero a un tipo polim´rfico. o El operador dynamic_cast<tipo&>(ref) comprueba en tiempo de ejecuci´n que ref puede o ser convertido al tipo destino (utiliza informaci´n de tipos en tiempo de ejecuci´n RTTI). Si o o no puede ser convertido lanza la excepci´n bad_cast. Nota: ref debe ser una referencia a o un tipo polim´rfico. o El operador const_cast<tipo*>(ptr_const_tipo) elimina la restricci´n constante de valor. o No se garantiza que funcione cuando se aplica a una entidad declarada originalmente como const. Esta distinci´n permite al compilador aplicar una verificaci´n de tipos m´ o o ınima para static_cast y haga m´s f´cil al programador la b´squeda de conversiones peligrosas representadas por reinterpret_cast. a a u Algunos static_cast son portables, pero pocos reinterpret_cast lo son. Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a 18 CAP´ ITULO 2. TIPOS SIMPLES Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a 2. Normalmente ser´n o e a constantes simb´licas y definiciones de tipos. . . Entidades globales son aquellas que han sido definidas fuera de cualquier bloque. . Se crean al principio de la ejecuci´n del programa y se destruyen al finalizar ´ste. sentencia_2. y expresamos la composici´n de sentencias a o o como una secuencia de sentencias terminadas cada una de ellas por el car´cter “punto y coma” a (.). Para ello enmarcamos la secuencia de sentencias entre dos llaves para formar un bloque: { sentencia_1. sentencia_2. sentencia_4. Su ´mbito a de visibilidad comprende desde el punto en el que se definen hasta el final del fichero. Distinguiremos dos clases: globales y locales.Cap´ ıtulo 3 Estructuras de control Las estructuras de control en C++ son muy flexibles. es obligatoria la declaraci´n de las entidades manipuladas o en el programa. . Por ello s´lo veremos algunas de ellas y utilizadas en contextos o y situaciones restringidas. sin embargo. } Es posible el anidamiento de bloques. } 3. Declaraciones globales y locales Como ya se vio en el cap´ ıtulo anterior. y permite agrupar una secuencia o de sentencias como una unidad.1. . { sentencia_1. 3. Un bloque es una unidad de ejecuci´n mayor que la sentencia. la excesiva flexibilidad puede dar lugar a estructuras complejas. { sentencia_3. } sentencia_n. o 19 . Sentencia. secuencia y bloque En C++ la unidad b´sica de acci´n es la sentencia. sentencia_n. . a cuando se solapa el ´mbito de visibilidad de dos entidades con el mismo identificador.1. . variable++. la entidad visible ser´ aquella que se encuentre declarada en el bloque de mayor nivel de anidamiento. --variable. // variable = variable + 1. } En C++ se pueden declarar/definir entidades en cualquier punto del programa. // variable = variable . Es decir.20 CAP´ ITULO 3. // variable = variable + expresion. // variable = variable * expresion. . . . declaracion_n. Adem´s. Sentencias de asignaci´n o La m´s simple de todas consiste en asignar a una variable el valor de una expresi´n calculada a o en base a los operadores mencionados anteriormente. a a { int x. Su ´mbito de visibilidad a comprende desde el punto en el que se definen hasta el final de dicho bloque.1. . . en caso de declaraciones de diferentes entidaa des con el mismo identificador en diferentes niveles de anidamiento de bloques. variable -= expresion. Universidad de M´laga a Dpto. sentencia_1.3. // variable = variable . } // x es vble de tipo int // x es vble de tipo float // x es vble de tipo int 3. } . // variable = variable + 1. . sentencia_m. variable = expresion. resultado = 30 * MAXIMO + 1. . . // variable = variable . Lenguajes y Ciencias de la Computaci´n o . { float x. Se crean al comienzo de la ejecuci´n del bloque (realmente en C++ se crean al ejecutarse la definici´n) y se destruyen o o al finalizar ´ste.expresion. se definen las siguientes sentencias de incremento/decremento: a ++variable. . Normalmente ser´n constantes simb´licas y variables locales. sin embargo nosotros restringiremos dichas declaraciones/definiciones al principio del programa para las entidades globales (constantes simb´licas y tipos) y al comienzo de los bloques para entidades locales o (constantes simb´licas y variables). . variable *= expresion. . variable--. en dicha a zona de solapamiento ser´ visible el identificador declarado/definido en el bloque m´s interno. variable += expresion. ESTRUCTURAS DE CONTROL Entidades locales son aquellas que se definen dentro de un bloque. o Respecto al ´mbito de visibilidad de una entidad. Ejemplo: int resultado. . . e a o { declaracion_1. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . |= expresion. de tal forma o o que permiten seleccionar flujos de ejecuci´n alternativos dependiendo de condiciones l´gicas. Su sintaxis es la o siguiente: Dpto.4. | expresion. . <<= expresion. Otra posibilidad es la sentencia de selecci´n condicional compuesta que tiene la siguiente sino taxis: if (condicion_logica) { secuencia_de_sentencias_v. >> expresion. La sentencia switch es otro tipo de sentencia de selecci´n en la cual la secuencia de sentencias o alternativas a ejecutar no se decide en base a condiciones l´gicas. &= expresion. si el resultado de evaluar la condicion_logica es Falso (false) se ejecuta la secuencia_de_sentencias_f. } y cuya sem´ntica consiste en evaluar la condicion_logica.. } y cuya sem´ntica consiste en evaluar la condicion_logica. %= expresion. 21 Nota: las sentencias de asignaci´n vistas anteriormente se pueden utilizar en otras muy diversas o formas. % expresion.4.´ 3. una relaci´n de pertenencia entre el o o valor de una expresi´n y unos determinados valores de tipo ordinal especificados. } else { secuencia_de_sentencias_f. ^= expresion. } con el flujo de control esperado. Sin embargo. ^ expresion. sino en funci´n del valor que o o tome una determinada expresi´n de tipo ordinal. } else { secuencia_de_sentencias_f. & expresion. o o La m´s simple de todas es la sentencia de selecci´n condicional if cuya sintaxis es la siguiente: a o if (condicion_logica) { secuencia_de_sentencias. y si su resultado es Verdadero a (true) entonces se ejecuta la secuencia_de_sentencias_v.. y si su resultado es Verdadero a (true) entonces se ejecuta la secuencia de sentencias entre las llaves. . } else if (cond_logica_3) { secuencia_de_sentencias_3. es decir. } else if (cond_logica_2) { secuencia_de_sentencias_2. >>= expresion. debido a que o dificultan la legibilidad y aumentan las posibilidades de cometer errores de programaci´n. SENTENCIAS DE SELECCION variable variable variable variable variable variable variable /= expresion. << expresion. o 3. pero nosotros restringiremos su utilizaci´n a la expresada anteriormente. } else if ( . ) { . La sentencia de selecci´n condicional se puede encadenar de la siguiente forma: o if (cond_logica_1) { secuencia_de_sentencias_1. // // // // // // // variable variable variable variable variable variable variable = = = = = = = variable variable variable variable variable variable variable / expresion. Sentencias de Selecci´n o Las sentencias de selecci´n alteran el flujo secuencial de ejecuci´n de un programa. Este ciclo iterativo consistente en evaluar la condici´n y ejecutar las sentencias se realizar´ MIENTRAS que la condici´n se eval´e a Verdadera o a o u y finalizar´ cuando la condici´n se eval´e a Falsa. En realidad se trata de la misma construcci´n while vista o a o anteriormente pero con una sintaxis diferente para hacer m´s palpable los casos en los que el control a de la iteraci´n tiene una clara inicializaci´n. default: secuencia_de_sentencias_f.5. a o u La sentencia for es semejante a la estructura FOR de Pascal o Modula-2. y si su valor coincide con valor_1 entonces se ejecuu ta la secuencia_de_sentencias_1. break. Si el valor de la expresi´n no coincide ı o con ning´n valor especificado. Bucles o Vamos a utilizar tres tipos de sentencias diferentes para expresar la repetici´n de la ejecuci´n o o de un grupo de sentencias: while. y un claro incremento hasta llegar al caso final. ESTRUCTURAS DE CONTROL en la cual se eval´a la expresion. incremento) { secuencia_de_sentencias. La o o sintaxis es la siguiente: for (inicializacion . } y es equivalente a: inicializacion.22 switch (expresion) { case valor_1: secuencia_de_sentencias_1. . condicion_logica . se ejecuta la secuencia de sentencias correspondiente a la etiqueta u default (si es que existe). } CAP´ ITULO 3. aunque en C++ toma una dimensi´n m´s amplia y flexible. case valor_4: secuencia_de_sentencias_3. 3. Posteriormente se vuelve a evaluar la condicion_logica y si vuelve a ser cierta se vuelve a ejecutar la secuencia_de_sentencias. . La sentencia while es la m´s utilizada y su sintaxis es la siguiente: a while (condicion_logica) { secuencia_de_sentencias. } en la cual primero se eval´a la condicion_logica. break. } Nota: es posible declarar e inicializar una variable (variable de control del bucle) en el lugar de la inicializaci´n. Dpto. Sentencias de Iteraci´n. En este caso especial. se ejecuta la secuencia_de_sentencias u completamente. incremento. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . while (condicion_logica) { secuencia_de_sentencias. break. y si es cierta. case valor_2: case valor_3: secuencia_de_sentencias_2. . su ´mbito de visibilidad es s´lamente hasta el final del o a o bloque de la estructura for. break. Si su valor coincide con valor_2 o con valor_3 se ejecuta la secuencia_de_sentencias_2 y as´ sucesivamente. for y do-while. tambi´n expresa la iteraci´n en la ejecuci´n de la secuencia de sentencias. } while (condicion_logica). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . pero a diferencia de e o o la primera estructura iterativa ya vista. u e en caso de ser cierta. Dpto. SENTENCIAS DE ITERACION. i < MAXIMO.5.´ 3. y si ´sta es cierta u e se repite el proceso. en esta estructura se ejecuta primero la secuencia_de_sentencias y posteriormente se eval´a la condicion_logica. ++i) { // hacer algo } // i ya no es visible aqui 23 La sentencia do while presenta la siguiente estructura do { secuencia_de_sentencias. donde primero se eval´a la condicion_logica y despu´s. se ejecuta la secuencia de sentencias. BUCLES for (int i = 0. ESTRUCTURAS DE CONTROL Dpto.24 CAP´ ITULO 3. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . y). . . } Funciones: encargados de realizar un c´lculo computacional y generar un resultado (normala mente calculado en funci´n de los datos recibidos) utilizable directamente: o int main() { int x = 8. . int y = 4. o Los subprogramas pueden ser vistos como un “mini” programa encargado de resolver algor´ ıtmicamente un subproblema que se encuentra englobado dentro de otro mayor. 4.1. . ordenar(x. int z. . Se les envia los datos necesarios y produce unos resultados que devuelve al lugar donde ha sido requerido: int main() { int x = 8. Funciones y procedimientos Los subprogramas (procedimientos y funciones) constituyen una unidad de ejecuci´n mayor o que el bloque.Cap´ ıtulo 4 Subprogramas. En ocasiones tambi´n e pueden ser vistos como una ampliaci´n/elevaci´n del conjunto de operaciones b´sicas (acciones o o a primitivas) del lenguaje de programaci´n. z = calcular_menor(x. } 25 . Funciones y procedimientos Dependiendo de su utilizaci´n (llamada) podemos distinguir dos casos: o Procedimientos: encargados de resolver un problema computacional. y). proporcion´ndole un m´todo para resolver nuevas opeo a e raciones. Proporcionan abstracci´n operacional al programador y constituyen una unidad o fundamental en la construcci´n de programas. int y = 4. . int b) { int menor. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .26 CAP´ ITULO 4. a a Todo este flujo de informaci´n se realiza a traves de los par´metros o argumentos del subprograma. Definici´n de subprogramas o Su definici´n podr´ ser como se indica a continuaci´n: o ıa o void ordenar(int& a. } } int calcular_menor(int a. o a 4. modificar´ el valor de otros datos. } return menor. Llamaremos argumentos o par´metros de salida a aquellos que se utilizan para transferir a informaci´n producida como parte de la computaci´n/soluci´n realizada por el subprograma. o o o Ejemplo: Dpto. } La definici´n de un subprograma comienza con una cabecera en la que se especifica en primer o lugar el tipo del valor devuelto por ´ste si es una funci´n. o o a nosostros s´lo permitiremos una unica utilizaci´n del return y deber´ ser al final del cuerpo de la o ´ o a funci´n. Aunque C++ es m´s flexible. o void en caso de ser un procedimiento. FUNCIONES Y PROCEDIMIENTOS 4. SUBPROGRAMAS.3. o a o a El cuerpo del subprograma determina la secuencia de acciones necesarias para resolver el problema especificado. el valor que toma tras la llamada vendr´ dado o a por el resultado de evaluar la expresi´n de la construcci´n return. e o A continuaci´n vendr´ el nombre del subprograma y la declaraci´n de sus par´metros. Por ejemplo los argumentos a y b de la o o funci´n calcular_menor anterior. En el caso de una funci´n. int& b) { if (a > b) { int aux = a. Par´metros por valor y por referencia a Llamaremos argumentos o par´metros de entrada a aquellos que se utilizan para recibir la a informaci´n necesaria para realizar la computaci´n. o Se declaran especificando el tipo y el identificador asociado. } else { menor = b. int b) { return ( (a < b) ? a : b ) . que significa que son valores que se copian desde el sitio de la llamada a los argumentos en el momento de la ejecuci´n del subprograma. y posiblemente generar´ nuevos valores. o Nota: la funci´n calcular_menor anterior tambi´n podr´ haber sido definida de la siguiente o e ıa forma: int calcular_menor(int a. } Normalmente la soluci´n de un subproblema o la ejecuci´n de una operaci´n depender´ del o o o a valor de algunos datos. a = b. b = aux.2. if (a < b) { menor = a. o Los argumentos de entrada se reciben por valor . 4. const int& b) { return ( (a < b) ? a : b ) . } As´ dividendo y divisor son argumentos de entrada y son pasados “por valor” como se ı. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Se declaran especificando el tipo. Subprogramas “en l´ ınea” La llamada a un subprograma ocasiona cierta p´rdida de tiempo de ejecuci´n en el control de e o la misma (sobrecarga). por lo que es necesario que se pasen por referencia que significa que ambos argumentos ser´n referencias a las variables que se hayan a especificado en la llamada. dividir(7. o Tambi´n es posible recibir los par´metros de entrada por referencia constante de tal forma e a que el par´metro ser´ una referencia al argumento especificado en la llamada. // ahora ’cociente’ valdra 2 y ’resto’ valdra 1 } 27 Su definici´n podr´ ser la siguiente: o ıa void dividir(int dividendo. SUBPROGRAMAS “EN L´ INEA” int main() { int cociente. Es decir. Llamaremos argumentos o par´metros de entrada/salida a aquellos que se utilizan para recibir a informaci´n necesaria para realizar la computaci´n.4. cociente. int divisor. si el par´metro se pasa por referencia es obligatorio a a que sea pasada como par´metro actual una variable que concuerde en tipo. el s´ ımbolo “ampersand” (&) y el identificador asociado. resto = dividendo % divisor. Por ejemplo los argumentos a y b del procedimiento ordenar anterior. sin embargo. int& cociente. Los argumentos de entrada/salida se reciben por referencia y se declaran como se especific´ anteriormente. int& resto) { cociente = dividendo / divisor.4. cualquier acci´n que se haga sobre ellas es equivalente o a que se realice sobre las variables referenciadas. y que tras ser modificada se transfiere o o al lugar de llamada como parte de la informaci´n producida resultado de la computaci´n del o o subprograma. } En la llamada a un subprograma. se declaran como se especific´ anteriormente para el paso por referencia. pero no podr´ modificarlo al ser una referencia constante. tomando as´ su a a ı valor. resto). Si el paso es por a referencia constante ((const int& x)) es posible que el par´metro actual sea una expresi´n de a o tipo compatible. 3. tanto cociente como resto son argumentos de salida (se o utilizan para devolver valores al lugar de llamada). En ese caso podemos especificar que el subprograma se traduzca como Dpto. vi´ anteriormente. int calcular_menor(const int& a. pero o anteponiendo la palabra reservada const. una expresi´n de un tipo compatible es adecuada para un o par´metro que se pase por valor. Sin embargo. int resto.4. Para ello. evitando as´ la sem´ntica de a ı a salida asociada al paso por referencia. Hay situaciones en las que el subprograma es muy peque˜o y nos interesa eliminar la sobrecarga n que produce su llamada. int z. for (i = 2.. Declaraci´n de subprogramas o Los subprogramas. int y = 4. desde el lugar donde ha sido declarado hasta el final del fichero. ++i) { // vacio } return (i >= x). // ver siguiente capitulo // ver siguiente capitulo const int MAXIMO = 100. // ahora ’z’ contine el calcular_menor numero de ’x’ e ’y’ . y).. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . ((i < x) && ( ! es_divisible(x.cpp -------------------------------------------#include <iostream> using namespace std. inline int calcular_menor(int a.. i))).. FUNCIONES Y PROCEDIMIENTOS c´digo en l´ o ınea en vez de como una llamada a un subprograma. es decir. } 4. } bool es_primo(int x) { int i. int calcular_menor(int a. Dicha declaraci´n se puede realizar de dos formas: una de ellas consiste simplemente o en definir el subprograma antes de utilizarlo. Para ello se especificar´ la palabra a reservada inline justo antes del tipo. a Para declarar un subprograma habra que especificar el tipo del valor devuelto (o void si es un procedimiento) seguido por el nombre y la declaraci´n de los argumentos igual que en la definici´n o o del subprograma. constantes y variables.. } // declaracion de ’calcular_menor’ Ejemplo de un programa que imprime los n´meros primos menores que 100. SUBPROGRAMAS. z = calcular_menor(x.. int b). inline bool es_divisible(int x. int b) { return ( (a < b) ? a : b ) . u //... y definirlo posteriormente.. En lugar de ello se terminar´ la declaraci´n a o con el caracter “punto y coma” (.5..fichero: primos1.). El ´mbito de visibilidad del subprograma o a ser´ global al fichero. deben ser declarados antes de ser utilizados. pero sin definir el cuerpo del mismo. al igual que los tipos. La otra posibilidad consiste en declarar el subprograma antes de su utilizaci´n.. int main() { int x = 8.28 CAP´ ITULO 4.. int y) { return ( x % y == 0 ).. } Dpto. ´ 4. DECLARACION DE SUBPROGRAMAS void escribir(int x) { cout << x << " ". ++i) { if (es_primo(i)) { escribir(i). // ver siguiente capitulo } int main() { primos(MAXIMO). // ver siguiente capitulo } void primos(int n) { for (int i = 1. // return 0.5. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . i < n. } } cout << endl.fin: primos1.cpp ------------------------------------------------ 29 Dpto. } //. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .30 CAP´ ITULO 4. FUNCIONES Y PROCEDIMIENTOS Dpto. SUBPROGRAMAS. Entrada La entrada de datos se realiza mediante el operador >> sobre la entidad cin especificando la variable donde almacenar el valor de entrada: cin >> contador .Cap´ ıtulo 5 Entrada / Salida b´sica a Para poder realizar entrada/salida b´sica de datos es necesario incluir las declaraciones de tipos a y operaciones que la realizan. Para ello habr´ que incluir la siguiente l´ a ınea al comienzo del fichero que vaya a realizar la entrada/salida: #include <iostream> Todas las definiciones y declaraciones de la biblioteca est´ndar se encuentran bajo el espacio de a nombres std (ver cap´ ıtulo 10). para utilizarlos libremente. Salida La salida de datos se realiza utilizando el operador << sobre la entidad cout especificando el dato a mostrar.1. escribir´ en la salida est´ndar el valor de contador. Por ejemplo: cout << contador . habr´ que poner la siguiente a declaraci´n al comienzo del programa (Nota: ´sto s´lo es v´lido en ficheros de implementaci´n y o e o a o bajo ciertas condiciones): using namespace std. 5. por lo que.2. incluso es posible leer varios valores simult´neamente: a cin >> minimo >> maximo . Tambien es posible escribir varios valores: a a cout << "Contador: " << contador . 5. 31 . si queremos escribir un salto de l´ ınea: cout << "Contador: " << contador << endl . max. cin >> min >> max . } bool es_primo(int x) { int i. i <= max. } } inline bool es_divisible(int x. cout << "Introduzca el rango de valores " . int& mayor) { if (mayor < menor) { int aux = menor. } void primos(int min. ENTRADA / SALIDA BASICA Dicho operador de entrada se comporta de la siguiente forma: salta los espacios en blanco que hubiera al principio. ’\r’. ’\t’.fichero: primos2. ’\n’). y lee dicha entrada hasta que encuentre alg´n caracter no v´lido para dicha u a entrada (que no ser´ leido y permanece hasta nueva entrada). ordenar(min.32 ´ CAP´ ITULO 5.cpp -------------------------------------------#include <iostream> using namespace std. dicha entrada se detine y se o pondr´ en estado err´neo. i))). menor = mayor. for (int i = min. } int main() { int min. ++i) { if (es_primo(i)) { cout << i << " " . el retorno de carro y la nueva linea (’ ’. void ordenar(int& menor. int y) { return ( x % y == 0 ). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . el tabulador. a o Se consideran espacios en blanco los siguientes caracteres: el espacio en blanco. Dpto. Ejemplo de un programa que imprime los n´meros primos existentes entre dos valores le´ u ıdos por teclado: //. int max) { cout << "Numeros primos entre " << min << " y " << max << endl. ++i) { // vacio } return (i >= x). } } cout << endl. max). a En caso de que durante la entrada surja alguna situaci´n de error. for (i = 2. mayor = aux. ((i < x) && ( ! es_divisible(x. x). int& dato) { entrada >> dato.fin: primos2. void leer_int(istream& entrada.2. } //. leer_int(cin. escribir_int(cout. y pueden ser pasadas como par´metros (por referencia no constante) a subprogramas: a #include <iostream> using namespace std. de salida y de error. x). cout y cerr se las denomina flujos de entrada. x). } int main() { int x. } void escribir_int(ostream& salida. // return 0.5. escribir_int(cerr.cpp ------------------------------------------------ A las entidades cin. } Dpto. max). ENTRADA 33 primos(min. int dato) { salida << dato << endl. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . 34 ´ CAP´ ITULO 5. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . ENTRADA / SALIDA BASICA Dpto. podremos utilizar la entidad (constante o variable) de dicho tipo como un todo o acceder a los diferentes elementos (campos) que lo componen. para declarar un agregado u o ı. y se conocen como “Agregados”. e 6.anyo = 2001. por ejemplo la variable a f nac. dado el tipo Meses definido en el Cap´ ıtulo 2.): a a f_nac. indicando su tipo y su identificador con el que referenciarlo. de fechas: 35 .Cap´ ıtulo 6 Tipos compuestos Los tipos compuestos surgen de la composici´n y/o agregaci´n de otros tipos para formar nuevos o o tipos de mayor entidad. Una vez declarada una entidad (constante o variable) de tipo registro. y posteriormente utilizarlo para definir constantes: const Fecha f_nac = { 20 . f_nac. “Arreglos” o mediante su nombre en ingl´s “Arrays”. que denominaremos “Registros” o “Estructuras” y la agregaci´n de o o elementos del mismo tipo. Meses mes. As´ por ejemplo.1. Una vez definido el tipo. o utilizarlo para definir variables: Fecha f_nac. Por ejemplo. Agregados o “Arrays” Un tipo agregado se especifica declarando el tipo base de los elementos que lo componen y el n´mero de elementos de que consta dicha agregaci´n. }. Existen dos formas fundamentales para crear tipos de mayor entidad: la composici´n de elementos. f_nac.2.dia = 18. 2001} . Registros o estructuras Un tipo registro se especifica enumerando los elementos (campos) que lo componen. 6.mes = Octubre. Febrero. podemos definir un tipo registro para almacenar fechas de la siguiente forma: struct Fecha { unsigned dia. podemos referirnos a ella en su globalidad (realizando asignaciones y pasos de par´metros) o acceder a sus componentes (campos) especific´ndolos tr´s el operador punto (. unsigned anyo. cit[i]. cit[i]. 2002 }.3. ´ El lenguaje de programaci´n C++ no comprueba que los accesos a los elementos de un agregado o son correctos y se encuentran dento de los limites v´lidos del array. ++i) { cit[i]. As´ mismo.dia = 18. CAP´ ITULO 6. Enero. cada uno del tipo Fecha. teniendo en cuenta que el primer elemento ocupa la posici´n 0 (cero) y el ultio o ´ mo elemento ocupa la posici´n numero_de_elementos-1. Acceso fuera de los limites 6.mes = Enero. es posible o ı declarar agregados de varias dimensiones. Un ejemplo de un agregado de dos dimensiones: const int N_PROVINCIAS = 8.anyo = 2002. cit[0]. especificaremos entre corchetes ([ y ]) la posici´n que ocupa. for (int i = 0.dia = 1. ı cit[0]. TIPOS COMPUESTOS estamos definiendo un agregado de 20 elementos. typedef Temp_Meses Temp_Prov[N_PROVINCIAS]. y la declaraci´n o Temp_Prov tmp_prv. que definir´ una variable seg´n el siguiente esquema: ıa u | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ |@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@| +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | Universidad de M´laga a 0 1 2 3 Dpto. const int N_MESES = 12. Si declaramos una variable de dicho tipo: Citas cit. cit[0].mes = Octubre. Por ejemplo cit[0] y cit[N_CITAS-1] o aluden al primer y ultimo elemento del agregado respectivamente. Lenguajes y Ciencias de la Computaci´n o .anyo = 2001. o de la siguiente forma: typedef float Temp_Prov[N_PROVINCIAS][N_MESES]. // ERROR. y cuyo identificativo es Citas. para acceder a un elemento concreto del agregado. typedef Fecha Citas[N_CITAS]. typedef float Temp_Meses[N_MESES]. por lo que ser´ responsabilidad a a del programador comprobar que as´ sea. i < N_CITAS. Agregados multidimensionales Los agregados anteriormente vistos se denominan de “una dimensi´n”. } cit[N_CITAS] = { 1.36 const int N_CITAS = 20. que en este ejemplo es 20. cada uno del tipo Fecha. ´ El lenguaje de programaci´n C++ no comprueba que los accesos a los elementos de un agregado o son correctos y se encuentran dento de los limites v´lidos del array. N_CITAS> Citas. ı Dpto. la operaci´n cit.4. especificaremos entre corchetes ([ y ]) la posici´n que ocupa. se debe incluir la biblioteca array de tr1. para acceder a un elemento concreto del agregado. Agregados o “Arrays” de la biblioteca Es posible utilizar el tipo array de la biblioteca TR1 para definir arrays.4. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Por ejemplo cit[0] y cit[cit. typedef array<Fecha.size()-1] aluden ´ o al primer y ultimo elemento del agregado respectivamente. para conocer el n´mero de elementos que componen un determinado arreglo. para declarar un agregado u o ı. 6. de fechas: const int N_CITAS = 20. estamos definiendo un agregado de 20 elementos. De forma similar se declaran agregados de m´ltiples dimensiones. u ´ ´ Nota: NO ESTA PERMITIDA LA ASIGNACION DIRECTA DE AGREGADOS. por lo que ser´ responsabilidad a a del programador comprobar que as´ sea. o #include <tr1/array> using namespace std::tr1. Para ello. Un tipo agregado se especifica declarando el tipo base de los elementos que lo componen y el n´mero de elementos de que consta dicha agregaci´n. As´ por ejemplo.6. teniendo en cuenta que el primer elemento ocupa la posici´n 0 (cero) y el o o ultimo elemento ocupa la posici´n size()-1. Si declaramos una variable de dicho tipo: Citas cit. La definici´n de ı o agregados de este tipo permite crear agregados mas robustos y con mejores caracter´ ısticas que el tipo predefinido visto en la secci´n anterior. AGREGADOS O “ARRAYS” DE LA BIBLIOTECA +---+---+---+---+---+---+---+---+---+---+---+---+ 4 | | | | | | |###| | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ 5 | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ 6 | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ 7 | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ 37 donde tmp_prv[2] se refiere a la variable marcada con el s´ ımbolo @ y tmp_prv[4][6] se refiere a la variable marcada con el s´ ımbolo #. as´ como abrir el espacio de nombres de tr1. y cuyo identificativo es Citas.size() u o proporciona dicho valor. N_MESES> Temp_Meses. i < cit. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .dia = 1. Agregados multidimensionales Los agregados anteriormente vistos se denominan de “una dimensi´n”.size(). y la declaraci´n o Temp_Prov tmp_prv. !=. // ERROR. Enero. const int N_MESES = 12. cit[0]. >. CAP´ ITULO 6. cit[i].> acepta la asignaci´n (=). cit[i]..mes = Octubre. siempre y cuando los componentes del agregado acepten dichos operadores. 6. typedef array<float.anyo = 2002. 2002 }. es posible o ı declarar agregados de varias dimensiones. <=. as´ como los operadores relacionales o ı ==. N_PROVINCIAS> Temp_Prov.38 cit[0].5. De forma similar se declaran agregados de m´ltiples dimensiones. cit[0]. Acceso fuera de los limites Un agregado de tipo array<. Un ejemplo de un agregado de dos dimensiones: const int N_PROVINCIAS = 8. TIPOS COMPUESTOS for (int i = 0. typedef array<Temp_Meses. >=.anyo = 2001. <.. } cit[N_CITAS] = { 1.dia = 18. ++i) { cit[i]. u Dpto.mes = Enero. que definir´ una variable seg´n el siguiente esquema: ıa u | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ |@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@|@@@| +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | |###| | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+ 0 1 2 3 4 5 6 7 donde tmp_prv[2] se refiere a la variable marcada con el s´ ımbolo @ y tmp_prv[4][6] se refiere a la variable marcada con el s´ ımbolo #. As´ mismo. tanto el paso por valor a como el paso por referencia act´an de igual forma: por referencia. Por lo tanto. por lo que no es posible pasarlos u por valor. es conveniente utilizar el manipulador setw (ver cap´ ıtulo 9) cin >> setw(MAX_CADENA) >> nombre. } Con respecto al paso de agregados “predefinidos”como par´metros. Par´metros de tipos compuestos a Respecto al paso de estructuras como par´metros. las estructuras se pueden pasar tanto por a valor como por referencia. que es una operaci´n muy eficiente tanto en tiempo como en memoria. se utilizar´ el paso por referencia constante para garantizar que dicho a a par´metro no ser´ modificado: a a void imprimir(const Fecha& fech) { cout << fech.7. typedef char Cadena[MAX_CADENA]. 6. CADENAS DE CARACTERES 39 6.dia << int(fech. Notas: Para evitar sobrepasar el l´ ımite del agregado durante la lectura. operaci´n costosa tanto en tiempo de o a o CPU como en consumo de memoria en el caso de tipos compuestos. Sin embargo. a o o como se ha visto en el ejemplo. En C++ las cadenas de caracteres se representan como un agregado de caracteres del tama˜o o n adecuado.6. Ejemplo: Dpto. En caso de o ser par´metros de entrada. utilizaremos siempre el paso por referencia.6.mes)+1 << fech. salvo en la inicializaci´n. Las cadenas de caracteres pueden tratarse de forma m´s adecuada mediante el tipo string. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Por ejemplo: const int MAX_CADENA = 10. a perteneciente a la biblioteca est´ndar de C++ que se describe en el cap´ a ıtulo 7. NO est´ permitida la asignaci´n directa de cadenas de caracteres. representa el siguiente esquema: 0 1 2 3 4 5 6 7 8 9 +---+---+---+---+---+---+---+---+---+---+ | P | e | p | e |\0 | ? | ? | ? | ? | ? | +---+---+---+---+---+---+---+---+---+---+ nombre Es posible aplicar los operadores de entrada y salida de datos (>> y <<) a las cadenas de caracteres. Esto sucede tanto con cadenas de caracteres constantes como con las variables. debido a que el paso por valor exige la copia del valor de su lugar de origen a la nueva localizaci´n del par´metro. donde la cadena de caracteres en s´ est´ formada por los caracteres comprendidos entre ı a el principio del agregado y un caracter especial que marca el final de la cadena. los par´metros de entrada se realizar´n mediante paso por a a referencia constante y los par´metros de salida y de entrada/salida se realizar´n mediante paso a a por referencia. y teniendo en cuenta la discusi´n anterior sobre la eficiencia (en tiempo o y memoria) del paso por referencia.6. Cadenas de caracteres Las cadenas de caracteres son un tipo de datos fundamental en cualquier lenguaje de programaci´n. Cadena nombre = "Pepe".anyo << endl. Este car´cter es el a ’\0’. 40 CAP´ ITULO 6. TIPOS COMPUESTOS void copiar(Cadena& destino, const Cadena& origen) { int i; for (i = 0; origen[i] != ’\0’; ++i) { destino[i] = origen[i]; } destino[i] = ’\0’; } 6.8. Par´metros de agregados de tama˜ o variable a n Hay situaciones en las cuales es conveniente que un subprograma trabaje con agregados de un tama˜o que dependa de la invocaci´n del mismo. Para ello se declara el par´metro mediante el n o a tipo base, el identificador del par´metro y el indicativo ([]) de que es un agregado sin tama˜o a n especificado (depender´ de la invocaci´n al subprograma). a o S´lo es posible pasar agregados de 1 dimensi´n sin especificar su tama˜o. Adem´s, la informao o n a ci´n sobre el tama˜o del agregado se pierde al pasarlo como agregado abierto, por lo que dicho o n tama˜o se deber´ tambi´n pasar como par´metro. n a e a Adem´s, el paso se realiza siempre por referencia sin necesidad de especificar el s´ a ımbolo &, y para asegurar que no sea modificado en caso de informaci´n de entrada, se realizar´ el paso de o a par´metros constante. Ejemplo: a void imprimir(int n, const int vct[]) { for (int i = 0; i < n; ++i) cout << vct[i] << " " ; } cout << endl; } void asignar_valores(int n, int vct[]) { for (int i = 0; i < n; ++i) vct[i] = i; } } typedef int Numeros[30]; typedef int Datos[20]; int main() { Numeros nm; Datos dt; asignar_valores(30, nm); imprimir(30, nm); asignar_valores(20, dt); imprimir(20, dt); } // numero de elementos // vector de enteros (paso por referencia constante) { // numero de elementos // vector de enteros (paso por referencia) { Nota: S´lo es v´lido declarar agregados abiertos como par´metros. No es posible declarar vao a a riables como agregados abiertos. Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a ´ 6.9. INICIALIZACION DE VARIABLES DE TIPO COMPUESTO 41 6.9. Inicializaci´n de variables de tipo compuesto o Es posible inicializar tanto las variables como las constantes en el momento de su definici´n. o Para ello utilizamos el operador de asignaci´n seguido por el valor (o valores entre llaves para tipos o compuestos) con el que se inicializar´ dicha entidad. En el caso de cadenas de caracteres el valor a a asignar podr´ ser tambi´n una cadena de caracteres constante literal; a e int main() { int x = 20; int y = x; Fecha f = { 20, Febrero, 1990 }; Cadena nombre = "pepe"; Temp_Prov tmp_prv = { { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, { 0.0, 0.0, 0.0, 0.0, } } 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 }, }, }, }, }, }, }, } Si en la declaraci´n de una variable no se inicializa con ning´n valor, dicha variable tendr´ un o u a valor inicial inespecificado. Con respecto a las definiciones de constantes, es obligatorio asignarles un valor en el momento de la definici´n. o Si en la inicializaci´n no se especifican todos los valores de cada elemento, los elementos no o especificados tomar´n un valor cero. a 6.10. Operaciones sobre variables de tipo compuesto Con respecto a las operaciones que se pueden aplicar a las entidades de tipo compuesto, hemos visto que se pueden pasar como par´metros, pero siempre lo realizaremos “por referencia”, y en el a caso de par´metros de entrada ser´n “por referencia constante”. a a Adem´s, en el caso de las estructuras o registros, tambien ser´ posible asignar una entidad a a a otra utilizando el operador de asignaci´n =. Sin embargo, esto no es posible para el caso de o agregados predefinidos, salvo en la inicializaci´n del mismo. o As´ mismo, no se aceptar´ que el tipo del valor devuelto por una funci´n sea un tipo compuesto, ı a o en este caso preferiremos que el valor devuelto se realice como un par´metro de salida utilizando a el “paso por referencia”. Tampoco est´n permitidos las comparaciones de ninguna clase entre entidades de tipo coma puesto. 6.11. Uniones Otra construcci´n util, aunque no muy utilizada, son las uniones, y sirven para compactar o ´ varias entidades de diferentes tipos en la misma zona de memoria. Es decir, todos las entidades definidas dentro de una uni´n compartir´n la misma zona de memoria, y por lo tanto su utilizaci´n o a o ser´ excluyente. Se utilizan dentro de las estructuras: a enum Tipo { COCHE, Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a 42 MOTOCICLETA, BICICLETA }; CAP´ ITULO 6. TIPOS COMPUESTOS struct Vehiculo { Tipo vh; union { float capacidad;// para el caso de tipo COCHE int cilindrada; // para el caso de tipo MOTOCICLETA int talla; // para el caso de tipo BICICLETA }; }; y su utilizaci´n: o Vehiculo xx; Vehiculo yy; xx.vh = COCHE; xx.capacidad = 1340.25; yy.vh = MOTOCICLETA; yy.cilindrada = 600; obviamente, los tipos de los campos de la uni´n pueden ser tanto simples como compuestos. o Es responsabilidad del programador utilizar los campos adecuados en funci´n del tipo que se o est´ almacenando. e 6.12. Campos de bits // // // // 22 bits sin signo 3 bits sin signo [unused] 3 bits sin signo 1 bit booleano struct PPN { unsigned PFN : 22; unsigned : 3; unsigned CCA : 3; bool dirty : 1; }; Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a Cap´ ıtulo 7 Biblioteca “string” de C++ La biblioteca string es un medio mas adecuado para tratar con cadenas de caracteres que los agregados de caracteres vistos en el cap´ ıtulo anterior. Para acceder a las facilidades proporcionadas por la biblioteca string de C++ debemos incluir el siguiente fichero de definici´n: o #include <string> y por supuesto, se encuentra bajo el espacio de nombres std, por lo que habr´ que usar la declaa raci´n: o using namespace std; Un string es una secuencia de caracteres, y la biblioteca proporciona tanto el tipo para contenerlos como las operaciones a realizar con ella. Declaramos un objeto de tipo string de la siguiente forma: string s1; Para saber el numero de caracteres (la longitud) del string: s1.lenght() // devuelve la longitud del string. s1.size() // devuelve la longitud del string. s1.empty() // devuelve si el string esta vacio. y accedemos a los caracteres individuales mediante indexaci´n: o s1[i] // accede al caracter que ocupa la posicion i (0 la primera) s1.at(i) // igual que el anterior, pero comprueba el acceso s1[0] // es el primer caracter s1[s1.lenght()-1] // es el ultimo caracter donde i debe estar entre 0 y s1.lenght()-1. En caso de acceder mas alla de los l´ ımites del string, at(i) lanza una excepci´n out_of_range (cap. 11). o Se puede declarar un string inicialmente vacio, o darle valores iniciales: string string string string string s1; // string vacio s2 = "pepeluis"; // string que contiene inicialmente "pepeluis" s3 = s2; // string que contiene inicialmente el valor de s2 s4(s2, 2); // copia del valor de s2 desde [2] hasta el final s5(s2, 3, 4); // copia del valor de s2 desde [3] hasta [6] char nombre[] = "juanlucas"; string s6(nombre, 4); // copia del valor de "juan" string s7(nombre, 3, 4); // copia del valor de "nluc" string s8(5, ’a’); // crea un string con 5 ’aes’ "aaaaa" 43 44 CAP´ ITULO 7. BIBLIOTECA “STRING” DE C++ Otras operaciones que se pueden realizar: asignaci´n (de strings, agregados de caracteres y caracter): o s1 = s3; s1 = "pepe"; s1[3] = ’a’; | s1.assign(s3, pos, ncar); | s1.assign("pepe", ncar); | s1.assign(5, ’a’); obtener la cadena como un agregado de caracteres terminado en \0: char* cad = s1.c_str(); s1.copy(dest, ncar, pos = 0); las siguientes operaciones de comparacion entre strings (y strings con agregados de caracteres): == != > < >= <= int c = s1.compare(s2); int c = s1.compare(pos, ncar, s2); int c = s1.compare(pos, ncar, s2, p2, n2); a˜adir strings: n s1 += s2; s1 += "pepe"; s1 += ’a’; s1.append(s2, pos, ncar); insertar strings s1.insert(3, s1.insert(3, s1.insert(0, s1.insert(0, s2); s2, p2, n2); "pepe"); "pepe", 2); concatenar strings string s9 = s1 + s2 + "pepe" + ’a’; buscar. En las siguientes busquedas, el patron a buscar puede ser un string, array de caracteres o un caracter. Si la posici´n indicada est´ fuera de los l´ o a ımites del string, entonces se lanza una excepci´n out_of_range. o string s = "accdcde"; unsigned i1 = s.find("cd", pos=0); unsigned i3 = s.find_first_of("cd", pos=0); unsigned i5 = s.find_first_not_of("cd", pos=0); //i1=2; s[2]==’c’&&s[3]==’d’ //i3=1; s[1]==’c’ //i5=0; s[0]!=’c’&&s[0]!=’d’ unsigned i2 = s.rfind("cd", pos=npos); //i2=4; s[4]==’c’&&s[5]==’d’ unsigned i4 = s.find_last_of("cd", pos=npos); //i4=5; s[5]==’d’ unsigned i6 = s.find_last_not_of("cd", pos=npos); //i6=6; s[6]!=’c’&&s[6]!=’d’ string::npos -> valor devuelto si no encontrado borrar una porcion del string string s = "accdcde"; s.erase(2, 3); s.erase(pos=0, ncar=npos); // s="acde" // s="" reemplazar una porcion del string Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a 45 string s = "accdcde"; s.replace(2, 3, "juan"); s.replace(pos, ncar, s2, p2, n2); // s = "acjuande" obtener subcadenas de un string string s1 = "accdcde"; string s2 = s1.substr(2, 3); // s2 = "cdc" string s2 = s1.substr(pos=0, ncar=npos); realizar operaciones de entrada/salida cout << s; cin >> s; getline(cin, s); getline(cin, s, delimitador); // // // // imprime el string salta espacios y lee hasta espacio lee hasta salto de linea (’\n’) lee hasta encontrar el delim. especificado reservar capacidad string::size_type mx = str.capacity(); str.reserve(tamano); Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a BIBLIOTECA “STRING” DE C++ Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .46 CAP´ ITULO 7. y el identificador del tipo: typedef int* Ptr_int. Punteros a 8. *p2. o int* p1. se utiliza el operador unario asterisco (*) precediendo al a nombre del puntero a trav´s del cual es referenciada: e int resultado = *p1 + 2. int* p2. un asterisco para indicar que es un puntero a un tipo. Por ejemplo. Declaraci´n o El tipo puntero es el tipo predefinido que nos da acceso a posiciones de memoria. y m´s cona cretamente a la memoria din´mica.1. Ptr_int pi. o a sin embargo. El tipo puntero se declara especificando el tipo de la entidad a apuntada. la siguiente declaraci´n no declara las variables como esperamos: o int* p1. si definimos el tipo Persona de la siguiente forma: 47 . // p1 es un puntero a entero y p2 es un entero la declaraci´n deber´ ser: o ıa int *p1. Desreferenciaci´n o Para acceder a una variable din´mica. // es una variable puntero a un entero sin embargo.Cap´ ıtulo 8 Memoria din´mica.2. // es una variable puntero a un entero Tambi´n se puede declarar una variable directamente: e int* pi. // obtiene el valor de la vble apuntado por p1 La utilizaci´n de la “Memoria Din´mica” para entidades de tipo simple no es de gran utilidad. Tambien se puede declarar un puntero gen´rico a cualquier tipo. e o void* Puntero_generico. p2. aunque para su utilizaci´n es e o necesario despu´s realizar una conversi´n al tipo correcto. 8. para el caso de entidades de tipos compuestos las posibilidades son muy diversas. string telefono. delete no har´ nada. // autoreferencia }.4. 8. Dpto. PUNTEROS Podemos definir el tipo puntero a persona de la siguiente forma: typedef Persona* PPersona. por lo tanto no es necesario comprobar a si un puntero es o no nulo antes de liberarlo. PPersona siguiente. struct Persona { string nombre. string telefono.telefono (*ppers). 8. Fecha fec_nacimiento.48 struct Persona { string nombre.nombre (*ppers). MEMORIA DINAMICA. de tal forma que el puntero nulo es el valor 0 o NULL.fec_nacimiento (*ppers).edad o m´s com´nmente para el caso que el tipo apuntado sea una estructura: a u ppers->nombre ppers->fec_nacimiento ppers->telefono ppers->edad Para liberar la memoria previamente solicitada: delete ppers. }. Fecha fec_nacimiento. int edad. Si se intenta liberar un puntero nulo. Cuando queramos especificar un puntero que no apunta a ninguna entidad utilizamos el 0 o NULL. int edad. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Estructuras autoreferenciadas Una de las principales aplicaciones de la Memoria Din´mica es el uso de estructuras autorefea renciadas: typedef struct Persona* PPersona. ´ CAP´ ITULO 8. y acceder a los elementos: (*ppers).3. Memoria Din´mica a Podemos solicitar memoria din´mica con el operador new seguido por el tipo de la entidad a a crear: PPersona ppers = new Persona. y con objeto de diferenciar el paso a a de un puntero a una variable del paso de un puntero a un agregado. dependiendo a o de su necesidad el n´mero de elementos del agregado. y no un puntero a un elemento.fec_nacimiento . Para liberar un agregado din´mico previamente solicitado: a delete [] pers.5. siendo el tipo devuelto por el operador new un puntero al tipo base. void leer(int n.´ 8. y un puntero a un agregado de elementos. int numeros[]) { cout << "Introduce " << n << " elementos " << endl.. MEMORIA DINAMICA DE AGREGADOS 49 8.. const int N_PERS = 20. AD_Personas pers = new Persona[N_PERS].. Por ejemplo para solicitar un agregado de 20 Personas: typedef Persona* AD_Personas.nombre pers[i]. como se indica a continuaci´n: u o int ad_enteros[] // agregado dinamico de enteros const int adc_enteros[] // agregado dinamico constante de enteros Ejemplo: #include <iostream> typedef int* AD_Enteros. Dpto.. se genera un puntero al primer elemento del agregado.. Una posibilidad para facilitar dicha tarea al programador consiste en definir el tipo de tal forma que indique que es un agregado din´mico. a a As´ mismo.. En tal a caso. y de hecho liberarlos de formas diferentes (con los corchetes en caso de agregados). no hay diferencia en el tipo entre un puntero a un elemento simple.5. y “por referencia” en caso de par´metros de salida y de entrada/salida. Memoria din´mica de agregados a Otra posibilidad consiste en solicitar memoria din´mica para un agregado de elementos. por lo que ser´ el propio programador el responsable de a diferenciarlos. Paso de par´metros de variables de tipo puntero a Las entidades de tipo puntero se pueden pasar como par´metros “por valor” en el caso de a par´metros de entrada. tambien es posible especificar si la entidad apuntada es o no constante: ı int* p1 const int* p2 int* const p3 const int* const p4 int* & r1 const int* & r2 int* const & r3 const int* const & r4 // // // // // // // // puntero puntero puntero puntero a un entero a un entero constante constante a un entero constante a un entero constante a un puntero a a un puntero a constante a un constante a un entero un entero constante puntero a un entero puntero a un entero const referencia referencia referencia referencia Respecto al paso de agregados din´micos como par´metros. incluyendo o n´. a 8. el paso de agregados din´micos a se realizar´ como el paso de un agregado abierto (constante o no). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Nota: En el caso de punteros. accedemos a cada elemento de igual forma como si fuera un agregado normal: pers[i].6.. ++i) { cin >> numeros[i]. i < n. AD_Enteros numeros. declarar punteros a funciones: ı typedef void (*PtrFun)(int dato). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . numeros = new int[nelm]. tambi´n a a e puede apuntar a variables est´ticas o autom´ticas. cin >> nelm. cout << *p << endl. // agregado dinamico cout << "Introduce el numero de elementos ". la asignaci´n de memoria o o din´mica alojada con el operador new. numeros). Ejemplo: int x = 3. MEMORIA DINAMICA.50 for (int i = 0.7. } return suma / float(n). cout << "Media: " << media(nelm. numeros) << endl. Para ello. // escribe 3 en pantalla *p = 5. es necesario poder obtener la direcci´n a a o de dichas variables. as´ mismo. ++i) { suma += numeros[i]. cout << x << endl. PUNTEROS } float media(int n. a los campos de una estuctura apuntada con el operador -> y acceder a un elemento de un agregado din´mico con []. El operador que nos devuelve la direcci´n donde se encuentra una determinada variable es el operador unario o “ampersand” (&). liberar la memoria con el operador delete. de tal forma que la variable puntero pueda acceder a ellas. } int main() { int nelm. // escribe 5 en pantalla 8. Punteros a subprogramas Es posible. 8.0. Adem´s. } ´ CAP´ ITULO 8. Operador de indirecci´n o En C++ un puntero. } 8. const int numeros[]) { float suma = 0. for (int i = 0. i < n. tambi´n es posible su paso como par´metros tanto “por a e a valor” como “por referencia”. delete [] numeros.8. Dpto. acceder a la a entidad apuntada con el operador *. adem´s de apuntar a variables alojadas en memoria din´mica.9. Tambi´n es posible tanto la comparaci´n a e o de igualdad como de desigualdad. Operaciones sobre variables de tipo puntero Las operaciones que se pueden aplicar a entidades de tipo puntero son principalmente la asignaci´n de otros punteros del mismo tipo o 0 para indicar el puntero nulo. int* p = &x. leer(nelm. 51 // vble puntero a funcion (devuelve void y recibe int) salida = imprimir_1. Dpto. no es necesario utilizar (*salida)(20). } // llamada. salida = imprimir_2. // asigna valor al puntero salida(20). // llamada. no es necesario utilizar (*salida)(20). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . } void imprimir_2(int valor) { cout << "Cuenta: " << valor << endl. } int main() { PtrFun salida.9. PUNTEROS A SUBPROGRAMAS void imprimir_1(int valor) { cout << "Valor: " << valor << endl. // asigna valor al puntero salida(20).8. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .52 ´ CAP´ ITULO 8. PUNTEROS Dpto. MEMORIA DINAMICA. y se almacenan en una zona de memoria intermedia denominada “buffer” de salida. o control y ficheros 9. para ello realizaremos la siguiente accion al comienzo de nuestro programa: #include <iostream> using namespace std.Cap´ ıtulo 9 Entrada / Salida. de donde el Sistema Operativo tomar´ la informaci´n para ser mostrada por pantalla.2. Para declarar simplemente los nombres de tipos: #include <iosfwd> En este cap´ ıtulo entraremos con m´s profundidad en las operaciones a realizar en la entraa da/salida. Cuando se va a mostrar alguna informaci´n de salida o cout << "Valor: " << val << endl. 9. los datos correspondientes a las teclas pulsadas se almacenan ı. c´mo controlar dichos flujos y comprobar su estado. y dicho valor se asignar´ a la variable o a especificada. As´ cuando se pulsa alguna tecla.1. y cerr como flujo de salida de errores estandar. Cuando un programa realiza una operaci´n de entrada de datos (cin >> valor). etc. sino que se convierten a un formato adecuado para ser impresos. Los flujos est´ndares a Los flujos existentes por defecto son cout como flujo de salida estandar. o Como se vi´ anteriormente. en una zona de memoria intermedia: el “buffer” de entrada. se convertir´n a a un valor del tipo especificado por la operaci´n de entrada. a o normalmente cuando se muestre un salto de l´ ınea. dichos datos no van directamente a la pantalla. Los operadores m´s simples para realizar la entrada y salida son: a 53 . accede al “buffer” de entrada y obtiene los valores o all´ almacenados si los hubiera. cin como flujo de entrada estandar. sino que se realiza a trav´s de “buffers” de entrada y salida respectivamente controlados e por el Sistema Operativo y son independientes de nuestro programa. Ampliaci´n. El “buffer” de entrada y el “buffer” de salida Ning´n dato de entrada o de salida en un programa C++ se obtiene o env´ directamente del/al u ıa hardware. as´ como la entrada/salida a ficheo ı ros. Una vez obtenidos los datos asociados a las teclas pulsadas. o esperar´ hasta que los haya (se pulsen una serie de teclas seguida ı a por la tecla “enter”). se produzca operaci´n de entrada de datos. para realizar operaciones de entrada/salida es necesario incluir las o definiciones correspondientes en nuestro programa. la entrada se realiza saltando los caracteres en blanco y saltos de l´ ınea hasta encontrar datos. AMPLIACION. o a o a 9. } As´ mismo se pueden realizar las siguientes operaciones para comprobar el estado de un flujo: ı cin >> valor.rdstate() & badbit) != 0 } else { ..3. . o que una operacion de salida fallo al generar los caracteres deseados Indica que todo es correcto (goodbit == iostate(0)) Para recuperar el estado erroneo de un flujo a un estado correcto (adem´s de otras acciones a pertinentes): Dpto. } | | | | | if (! cin) { // cin. } Indica que una operacion de entrada alcanzo el final de una secuencia de entrada Indica perdida de integridad en una secuencia de entrada o salida (tal como un error irrecuperable de un fichero) Indica que una operaci\’on de entrada fallo al leer los caracteres esperados.. Estado . Si el dato leido se puede convertir al tipo de la variable que lo almacenar´ entonces la a operaci´n ser´ correcta. se puede realizar una pregunta directamente sobre ´l: e e if (cin) { // !cin. S´lo es aplicable a los tipos de datos o predefinidos y a las cadenas de caracteres. en otro caso la operaci´n ser´ incorrecta.. >> para la entrada de datos sobre un flujo de entrada. cout << "El valor es " << i << endl.fail() // buen estado cin >> valor.fail()) { // ocurrio un error y prox op fallara // (cin. Para comprobar si un determinado flujo se encuentra en buen estado para seguir trabajando con ´l o no.rdstate() & (badbit | failbit))!=0 } else { . Control de flujos.... } //eofbit: // //badbit: // //failbit: // // //goodbit: | | | | | | | | | | | | | cin >> valor. if (cin.. } if (cin..eof()) { // Fin de fichero //(cin. S´lo es aplicable a los tipos de datos o predefinidos y a las cadenas de caracteres.bad()) { // flujo en mal estado //(cin. ENTRADA / SALIDA. donde endl representa el ”salto de l´ ınea”... Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . cin >> valor1 >> valor2.rdstate() == 0) } else { // entrada erronea } if (cin.rdstate()&eofbit)!=0 } else { .good()) { // no error flags set // (cin. . CONTROL Y FICHEROS << para la salida de datos sobre un flujo de salida..fail() // mal estado cerr << "Error en el flujo" << endl.54 ´ CAP´ ITULO 9... if (cin. cin. ’\n’). // anade los flags especificados 55 Por ejemplo: if (cin) { int valor. // pone el estado a ios::goodbit cin. // borra mask y activa el flag especificado Los flags pueden ser: ios::skipws ios::adjustfield ios::left // saltar los espacios en blanco (en entrada) // mascara de justificacion // justificacion izquierda Universidad de M´laga a Dpto.9.width(5).setstate(flags). // pone el estado al indicado ios::iostate e = cin.4. // devuelve los flags actuales cout. | cout << "Entrada erronea" << endl. ENTRADA/SALIDA FORMATEADA [ios::goodbit | ios::failbit | ios::eofbit | ios:badbit] cin. } else { char entrada[128]. // pone los flag a los especificados (|) cout. cout << "Entrada erronea: " << entrada << endl. cin.width(5). // activa el flag especificado cout. cin >> number. // desactiva el flag especificado cout. | cin. } | if (cin) { | int valor.ignore(3000. Lenguajes y Ciencias de la Computaci´n o . cin >> setw(128)>> entrada.unsetf(flag). if (cin) { cout << valor << endl.fill(’#’).rdstate(). // proxima lectura como maximo 4 caracteres cout. Por defecto ’ ’. // digitos significativos de numeros reales a 4 cout. Try again" << endl. cin >> valor.setf(flag. } } int read_int() { int number. cin. // caracter de relleno a ’#’.clear().flags(ios::fmtflags).setf(flag).clear(). | if (cin) { | cout << valor << endl. cin.clear(flags). cout. // anchura de campo a 5 proxima salida cin. Entrada/Salida formateada Las siguientes operaciones son utiles para alterar el formato en que se producen los datos del ´ flujo: cout. ’\n’). | } | } | | 9. | } else { | cin. | cin >> valor. while (!cin) { cout << "Error.flags().clear().4. mask).ignore(10000.clear(). } return number. cin >> number.precision(4). // imprime 4. cout << setprecision(2) << 4. Operaciones de salida Adem´s de las operaciones ya vistas. << ends.. ENTRADA / SALIDA.567.. CONTROL Y FICHEROS ios::right ios::internal ios::basefield ios::dec ios::oct ios::hex ios::floatfield ios::fixed ios::scientific ios::showbase ios::showpoint ios::showpos ios::uppercase ios::unitbuf // justificacion derecha // justificacion interna // // // // mascara para indicar la base entrada/salida en base decimal entrada/salida en base octal entrada/salida en base hexadecimal // mascara para notacion cientifica // no usar notacion cientifica (exponencial) // usar notacion cientifica (exponencial) // // // // mostrar prefijo que indique la base (0 0x) mostrar siempre el punto decimal mostrar el signo positivo usar mayusculas en representacion numerica // forzar la salida despues de cada operacion La precision en el caso de formato por defecto de punto flotante.567. hex << 27. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . // imprime 4. indica el m´ximo n´mero de a u d´ ıgitos.5.6 cout. << flush.setf(ios::fixed. << endl. // // // // // salta espacio en blanco salta espacio en blanco antes de la entrada de datos fuerza la salida envia un salto de linea (’\n’) y fuerza envia un fin de string (’\0’) para utilizar los siguientes manipuladores es necesario incluir el siguiente fichero de definici´n: o #include <iomanip> cout << setprecision(2) << 4. // imprime ’##234’ cin >> setw(10) >> nombre. cout << . cout cout cout cout << << << << dec << 27.. cin >> ws >> entrada. oct << 27. // lee como maximo 9 caracteres (+ ’\0’) // // // // imprime imprime imprime imprime 27 1b 33 true 9. cout << .. ios::floatfield).setf(ios::scientific. AMPLIACION. En caso de formato fixed o scientific indica en n´mero de d´ u ıgitos despues del punto decimal. Ademas de las anteriores operaciones que afectan al flujo de forma general (salvo width).56 ´ CAP´ ITULO 9..567. boolalpha << true. cout << setprecision(2) << 4. // imprime ’ 234’ cout << setfill(’#’) << setw(5) << 234. cout << .57 cout.57e+00 cout << setw(5) << 234. ios::floatfield). es posible aplicar las siguientes operaciones a los flujos a de salida: Dpto.. los siguientes manipuladores permiten afectar las operaciones de entrada/salida s´lo en el momento o que se estan efect´ando: u cin >> ws. // imprime 4. // lee ’tam’ caracteres y los almacena en el string // NO pone el terminador ’\0’ al final del string Tambi´n es posible leer un string mediante las siguientes operaciones. Operaciones de entrada Adem´s de las vistas anteriormente (no las de salida). delimitador). // lee un string como maximo hasta ’tam-1’ o hasta salto de linea // anade el terminador ’\0’ al final de str // el caracter de salto de linea SI se elimina del flujo cin.6. cout. int tam).sync().getline(char str[].get(char& c). // lee un string como maximo hasta ’tam-1’ o hasta que se lea ’delim’ // anade el terminador ’\0’ al final de str // el caracter delimitador SI se elimina del flujo cin.put(’#’). // lee un string como maximo hasta ’tam-1’ o hasta salto de linea // anade el terminador ’\0’ al final de str // el caracter de salto de linea NO se elimina del flujo cin.9..get(char str[].pcount(). OPERACIONES DE ENTRADA cout. int tam.peek(). } . se pueden aplicar las siguientes operaa ciones a los flujos de entrada: Para leer un simple caracter: int n = cin. int tam). // lee un caracter de entrada int n = cin. int tam).6. getline(cin. char delim). especificado Universidad de M´laga a . char delim).flush(). int tam). // creacion del centinela en << if (!centinela) { setstate(failbit).get(). // lee un caracter de entrada o EOF cin. str). // imprime un caracter cout. } // devuelve el numero de caracteres escritos // fuerza la salida del flujo // sincroniza el buffer 57 9. getline(cin. cout.// imprime ’tam’ caracteres del ’string’ int n = cout. return(cout). Dpto.write(char str[]. e cin >> str. int tam.. str. { ostream::sentry centinela(cout).get(char str[]. // lee un string como maximo hasta ’tam-1’ o hasta que se lea ’delim’ // anade el terminador ’\0’ al final de str // el caracter delimitador NO se elimina del flujo cin. Lenguajes y Ciencias de la Computaci´n o // salta espacios y lee hasta espacios // lee hasta salto de linea (’\n’) // lee hasta encontrar el delim. // devuelve el prox caracter (sin leerlo) Para leer cadenas de caracteres (una l´ ınea cada vez): cin.read(char str[].getline(char str[]. El buffer es el encargado de almacenar los caracteres (antes de leerlos o escribirlos) y definen adem´s a su comportamiento. que ser´n leidos por getline. ENTRADA / SALIDA. // elimina los caracteres del buffer cin.. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . } .7.putback(char ch). // actualizar y obtener el ptr anterior Ejemplo donde se desactiva el buffer si el nivel de verbosidad no supera un umbral (vease mas ejemplos en Seccion 17. streambuf* pbuff1 = stream. // devuelve al flujo el ultimo caracter leido cin. cout.4). // obtener el ptr al buffer streambuf* pbuff2 = stream..exceptions(ios::badbit | ios::failbit | ios::eofbit). // devuelve el numero de caracteres leidos cin.rdbuf()->in_avail()). ya que >> dejara los separadores en el buffer.sync(). AMPLIACION. // lee caracteres disponibles (hasta n) n = cin. o 9.readsome(char* p.ignore([int n][.unget(). Buffer Se puede acceder al buffer de un stream. tanto para obtener su valor como para modificarlo. cin.4): //------------------------------------------------------------------------#include <iostream> using namespace std. // numero de caracteres disponibles en el buffer cin. CONTROL Y FICHEROS Notese que realizar una operacion getline despues de una operacion con >> puede tener complicaciones. int n). e a int n = cin.ignore(cin. // devuelve al flujo el caracter ’ch’ { istream::sentry centinela(cin). Es posible la redireccion de los streams gracias a los bufferes (vease 17. int delim]). // ignora cars hasta ’n’ o ’delim’ cin. linea). Para evitar a este problema (leera una cadena que sea distinta de la vacia): void leer_linea_no_vacia(istream& ent.exceptions(ios::badbit | ios::failbit | ios::eofbit).58 ´ CAP´ ITULO 9. int n = cin. Dpto.rdbuf(). la excepci´n lanzada es del tipo ios::failure. string& linea) { ent >> ws.exceptions().gcount(). Es donde reside la inteligencia de los streams. // salta los espacios en blanco y rc’s getline(ent.rdbuf(pbuff1). } std::ios::sync_with_stdio(false). // leera la primera linea no vacia } Las siguientes operaciones tambi´n est´n disponibles. return(cin). // sincroniza el buffer Para hacer que lance una excepci´n cuando ocurra alg´n error: o u ios::iostate old_state = cin. ostream::traits_type> streambuf_type.rdbuf()->in_avail(). // creacion del centinela en >> if (!centinela) { setstate(failbit). typedef basic_streambuf<ostream::char_type. // } // static void set_level(unsigned l) { verbose_level = l.rdbuf(l>verbose_level()?NULL:os.flush(). l). inline unsigned verbose_level(unsigned l = -1U) { static unsigned verb_level = 0. BUFFER //------------------------------------------------------------------------// class VerboseOut : public std::ostream {}. } inline std::ostream& verb(std::ostream& os. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . l). unsigned l) { // os. // VerboseOut VerboseHandler::out. } inline std::ostream& verb(unsigned l) { return verb(std::cerr. // class VerboseMngr { // friend std::ostream& operator<< (std::ostream& out. // class VerboseHandler { // friend std::ostream& operator<< (std::ostream& out. unsigned l) { static VerboseOut out. unsigned res = verb_level.9.rdbuf(l>verbose_level?NULL:os. if (l != -1U) { verb_level = l. // out. // out. } // }. // const class VerboseMngr& vm). } return res. // } // inline std::ostream& verb(unsigned l) { // return VerboseHandler::set(std::cerr. // return out. // static VerboseOut out.rdbuf()). // friend void verbose_level(unsigned l). // VerboseMngr(unsigned l) : lv(l) {} // }. // } //------------------------------------------------------------------------class VerboseOut : public std::ostream {}.lv). vm. // } // inline VerboseMngr verbose(unsigned l) { // return VerboseMngr(l).rdbuf()). // static std::ostream& set(std::ostream& os.flush().7. // //-----------------------------------// inline void verbose_level(unsigned l) { // VerboseHandler::set_level(l). // unsigned lv. os. // friend VerboseMngr verbose(unsigned l). // const class VerboseMngr& vm). out. // inline std::ostream& operator<< (std::ostream& out. // } // //-STATIC-INIT-----------------------// unsigned VerboseHandler::verbose_level = 0. // static unsigned verbose_level.flush(). out. // friend std::ostream& verb(unsigned l).flush(). const VerboseMngr& vm) { // return VerboseHandler::set(out. 59 Dpto. return out. endl. endl. endl. simplemente cambiando las variables cin y cout por las correspondientes variables que especifican cada fichero. Ficheros Las operaciones vistas anteriormente sobre los flujos de entrada y salida estandares se pueden aplicar tambien sobre ficheros de entrada y de salida. endl. endl. endl. endl.open(char nombre[] [. unsigned lv. endl. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . VerboseMngr(unsigned l) : lv(l) {} }. endl. Ficheros de entrada Veamos como declaramos dichas variables para ficheros de entrada: ifstream fichero_entrada. const VerboseMngr& vm) { return verb(out.9. } inline VerboseMngr verbose(unsigned l) { return VerboseMngr(l). // declara un fichero de entrada fichero_entrada. const class VerboseMngr& vm). // abre el fichero donde los modos posibles. } //------------------------------------------------------------------------int main() { verbose_level(2). inline std::ostream& operator<< (std::ostream& out. endl. friend VerboseMngr verbose(unsigned l). 0" 1" 2" 3" 4" << << << << << endl. vm. ENTRADA / SALIDA. combinados con or de bits (|): Dpto.60 ´ CAP´ ITULO 9.lv). int modo]). CONTROL Y FICHEROS } class VerboseMngr { friend std::ostream& operator<< (std::ostream& out. endl. cerr cerr cerr cerr cerr << << << << << verbose(0) verbose(1) verbose(2) verbose(3) verbose(4) << << << << << << << << << << "Prueba-1 "Prueba-1 "Prueba-1 "Prueba-1 "Prueba-1 0" 1" 2" 3" 4" << << << << << endl. 0" 1" 2" 3" 4" << << << << << endl. Para ello es necesario incluir la siguiente definici´n: o #include <fstream> 9. endl.8. verb(0) verb(1) verb(2) verb(3) verb(4) cerr cerr cerr cerr cerr << << << << << "Prueba-2 "Prueba-2 "Prueba-2 "Prueba-2 "Prueba-2 << << << << << verbose(0) verbose(1) verbose(2) verbose(3) verbose(4) "Prueba-3 "Prueba-3 "Prueba-3 "Prueba-3 "Prueba-3 } //------------------------------------------------------------------------- 9. AMPLIACION. combinados con or de bits (|) son los anteriormente especificados. Nota: si se va a abrir un fichero utilizando la misma variable que ya ha sido utilizada (tras el close()). ios::beg|ios::cur|ios::end).11. a e Para posicionar el puntero de lectura del fichero (puede coincidir o no con el puntero de escritura): n = cin. // pone la posicion de lectura a ’pos’ cin. // devuelve la posicion de lectura cin.close(). int modo]). se deber´ utilizar el m´todo clear() para limpiar los flags de estado. int modo]).seekg(pos).tellg(). Para cerrar el fichero fichero_salida. Nota: si se va a abrir un fichero utilizando la misma variable que ya ha sido utilizada (tras el close()). Para cerrar el fichero fichero_entrada.seekp(offset.10.open(char nombre[] [. // pone la posicion de escritura relativa 9. // declara un fichero de salida fichero_salida.9. // pone la posicion de escritura a ’pos’ cout. se deber´ utilizar el m´todo clear() para limpiar los flags de estado.10. Otra posibilidad es declarar la variable y abrir el fichero simult´neamente: a ofstream fichero_salida(char nombre[] [. int modo]).seekp(pos).seekg(offset. // pone la posicion de lectura relativa 9. a e Para posicionar el puntero de escritura del fichero (puede coincidir o no con el puntero de lectura): n = cout. Ejemplo de ficheros Ejemplo de un programa que lee caracteres de un fichero y los escribe a otro hasta encontrar el fin de fichero: Dpto. // abre el fichero donde los modos posibles. Ficheros de salida ofstream fichero_salida. // devuelve la posicion de escritura cout. ios::beg|ios::cur|ios::end).close().tellp(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . FICHEROS DE SALIDA ios::in ios::out ios::app ios::binary ios::ate ios::trunc // // // // entrada salida posicionarse al final antes de cada escritura fichero binario 61 // abrir y posicionarse al final // truncar el fichero a vacio Otra posibilidad es declarar la variable y abrir el fichero simult´neamente: a ifstream fichero_entrada(char nombre[] [. if (f_ent) { ofstream f_sal(salida.close(). f_ent.13.rdbuf(). // no es necesario } f_ent. while (f_ent && f_sal) { // mientras no haya un error o EOF f_sal.rdbuf(). if (f_sal) { char ch. ENTRADA / SALIDA. Flujo de entrada desde una cadena Es posible tambi´n redirigir la entrada desde un string de memoria.close(). AMPLIACION. if (f_ent) { ofstream f_sal(salida. ios::in | ios::out). f_sal. Dpto. CONTROL Y FICHEROS #include <iostream> #include <fstream> void copiar_fichero(const string& salida. ok = f_ent.c_str()). istream& in) { return out << in. } 9. bool& ok) { ok = false. 9.c_str()). const string& entrada.get(ch). bool& ok) { ok = false.good(). // const char entrada[10] = "123 452". f_sal. // no es necesario } } void copiar_fichero_2(const string& salida. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .eof() && f_sal.c_str()).c_str()).close(). const string& entrada. // no es necesario } f_ent. Veamos como se realiza: e #include <sstream> // const char* entrada = "123 452". ifstream f_ent(entrada. if (f_sal) { f_sal << f_ent. } ok = f_ent. Ficheros de entrada/salida Para ficheros de entrada/salida utilizamos el tipo: fstream fich_ent_sal(char nombre[].eof() && f_sal. ifstream f_ent(entrada.close().62 ´ CAP´ ITULO 9.get(ch).good(). // no es necesario } } inline ostream& operator<< (ostream& out.12.put(ch). f_ent. str_entrada >> valor3..str("cadena inicial"). str_entrada >> valor1. Flujo de salida a una cadena As´ mismo. istringstream str_entrada(entrada). FLUJO DE SALIDA A UNA CADENA const string entrada = "123 452". // devuelve la longitud de la cadena string salida = str_salida.str().15..9.str("nueva entrada") 63 9...14.. tambi´n es posible redirigir la salida a un string en memoria: ı e #include <sstream> ostringstream str_salida.. str_salida << 123.. : : istream<> ostream<> ^ ^ | | +--------------+------+----+ +----+------+---------------+ | | | | | | istringstream<> ifstream<> iostream<> ofstream<> ostringstream<> ^ | +-----+-----+ | | fstream<> stringstream<> Dpto.:. // salida tendra "123" n = str_salida. str_salida. Jerarqu´ de clases de flujo est´ndar ıa a ios_base ^ | ios<> ^ : ... // EOF str_entrada. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .. str_entrada >> valor2. // valor1 = 123. 9. // valor2 = 452.14.pcount(). 64 ´ CAP´ ITULO 9. AMPLIACION. CONTROL Y FICHEROS Dpto. ENTRADA / SALIDA. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . const Complejo& x. Una primera ventaja de la existencia de m´dulos es o o el hecho de que si se modifica algo interno en un determinado m´dulo. o su fichero de definici´n y de implementaci´n. y no todo el programa completo. poner todo el c´digo encargado de resolver un determinado problema en un o m´dulo nos permite aislarlo del resto. lo que se convierte en una ventaja indudable en caso de programas grandes. }.. “. Normalmente los ficheros de implementaci´n tendr´n una extensi´n “.hh”.hxx”. A este o o u fichero tambi´n se le denomina “fichero cabecera”..cc”. “..hpp -----------------------------------------#ifndef _complejos_ // guarda para evitar inclusion duplicada #define _complejos_ // struct Complejo { float real. s´lo ser´ necesario volver o o a a compilar dicho modulo. Otra ventaja de los m´dulos es que permiten aumentar la localidad del c´digo y aislarlo del o o exterior. const Complejo& y). float imag. ´ sino que se distribuyen en varios m´dulos. o a o Las declaraciones en los ficheros de definici´n vendr´n dadas entre las siguientes definiciones o a de compilaci´n condicional.Cap´ ıtulo 10 M´dulos o Cuando se desarrollan programas en el mundo real. Por ejemplo para el fichero “complejos. 10. “. void sumar(Complejo& res. con lo que futuras modificaciones ser´n m´s f´ciles de o a a a realizar.cxx”. e As´ un programa completo se compone de normalmente de varios m´dulos. float imag). .hpp”. y un fichero que contiene las declaraciones de tipos. y o a o los ficheros de definici´n tendr´n una extensi´n “. normalmente no se utiliza un unico fichero.h”. de tal forma que tenga acceso a las declaraciones p´blicas o u de este. .cpp”. cada uno con ı. es decir.fichero: complejos. “. y de un m´dulo principal donde reside la funci´n o o o o principal main. “... Para que un m´dulo pueda hacer uso de las utilidades que proporciona otro m´dulo deber´ ino o a cluir su definici´n (su fichero cabecera). o u Llamaremos la implementaci´n del m´dulo al fichero que contiene la parte privada del m´dulo. o o o y denominaremos definici´n del m´dulo al fichero que contiene la parte p´blica del mismo. 65 . Definici´n e implementaci´n o o Normalmente un m´dulo se compone de dos ficheros: uno donde aparece el c´digo que resuelve o o un determinado problema o conjunto de problemas (parte privada). subprogramas y constantes globales que el m´dulo ofrece (parte p´blica). float real.hpp” o //. void Crear(Complejo& num.1. float real. o o an´nimo ser´ visible en el m´dulo de implementaci´n donde se encuentre. el m´dulo de implementaci´n tambi´n deber´ incluir al m´dulo de definici´n con objeto ı o o e a o o de obtener y contrastar las definiciones alli especificadas.2. }. const Complejo& y). const Complejo& x. const Complejo& x. existen espacios de nombre an´nimos para crear zonas privadas a cada m´dulo de a o o implementaci´n. const Complejo& y).hpp ---------------------------------------------//.cpp -----------------------------------------#include "complejos. void mult(Complejo& res.fin: complejos.66 ´ CAP´ ITULO 10. que es una forma de agrupar bajo una o denominaci´n un conjunto de declaraciones y definiciones. a o //. } // complejos #endif //. float imag). const Complejo& x. pero no ser´ visible o a o o a (ser´ privada) fuera del m´dulo. MODULOS void mult(Complejo& res.fin: complejos. void sumar(Complejo& res. As´ cualquier declaraci´n/definici´n realizada dentro de un espacio de nombres o ı.hpp" as´ mismo. #endif //. 10.hpp -----------------------------------------#ifndef _complejos_ // guarda para evitar inclusion duplicada #define _complejos_ // /* * Declaraciones publicas del modulo */ namespace complejos { struct Complejo { float real.hpp" #include <cmath> /* * Implementacion privada del modulo */ namespace { using namespace std. Dpto. void Crear(Complejo& num. float imag.fichero: complejos. a Adem´s. surgen los espacios de nombres. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . const Complejo& y). Espacios de nombre Con objeto de evitar posibles problemas de identificadores repetidos cuando se incluyen diferentes definiciones de m´dulos.hpp ---------------------------------------------- Para que un m´dulo pueda utilizar las operaciones aportadas por otro m´dulo deber´ incluir o o a su definici´n de la siguiente forma: o #include "complejos.fichero: complejos. de tal forma que dicha denominaci´n o o ser´ necesaria para identificar y diferenciar cada entidad declarada. theta). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . struct Polar { float rho.imag = imag. cartesiana_a_polar(p2. const Complejo& x.imag = x. float real. float imag) { num. pr. cartesiana_a_polar(p1.rho = p1. pr).theta + p2.real = x. pol.theta. p1. } void cartesiana_a_polar(Polar& pol. res. const Complejo& x.rho.real = pol.imag)). const Complejo& y) { res. num.theta = p1.theta).imag.real) + sq(cmp. pr. inline float sq(float x) { return x*x.rho = sqrt(sq(cmp.rho * cos(pol. } } /* * Implementacion correspondiente a la parte publica del modulo */ namespace complejos { void Crear(Complejo& num.imag = pol. } void polar_a_cartesiana(Complejo& cmp. float theta. const Polar& pol) { cmp.real = real. polar_a_cartesiana(res. const Complejo& cmp) { pol.real. 67 Dpto.2. y).rho * p2. p2.imag. cmp. const Complejo& y) { Polar pr.rho * sin(pol.real). }.real + y. cmp.10. } void sumar(Complejo& res. x).imag + y.theta = atan2(cmp. ESPACIOS DE NOMBRE using namespace complejos. } void mult(Complejo& res. Es decir. 6. 6. 6. 5. MODULOS } // complejos //. Ejemplo: using namespace std.0). Nota: no es adecuado aplicar la directiva using dentro de ficheros de definici´n (cabeceras) ya o que traer´ muchos identificadores al espacio de nombres global. // si ha sido definido el alias anterior complejos::Crear(num. ya que ha sido declarado mediante la directiva using. Dpto. complejos::Crear(num.0). Crear(num. Complejo num. Nota: Todas las operaciones de la biblioteca estandar se encuentran dentro del espacio de nombres std.0.cpp ---------------------------------------------- Para utilizar un m´dulo definido con “espacios de nombre” hay varias formas de hacerlo: o Se puede crear un alias para un espacio de nombres para facilitar la cualificaci´n: o namespace NC = complejos.68 } ´ CAP´ ITULO 10. utilizo Complejo sin cualificar. using namespace complejos. Utilizando la directiva using namespace hacemos disponible todos los identificadores de dicho espacio de nombres completo sin necesidad de cualificar. y para utilizarlas es necesario aplicar lo anteriormente expuesto en cuanto a la directiva using. Sin embargo. Complejo num.0. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . debo cualificar Crear ya que no ha sido declarado mediante using.0. La siguiente forma consiste en utilizar la directiva using para utilizar los identificadores sin cualificar(cualificaci´n iml´ o ıcita): using complejos::Complejo. 5. en ficheros de definici´n ıa o se deber´ utilizar la cualificaci´n expl´ ıa o ıcita de nombres en vez de la directiva using. La primera forma consiste en utilizar cada identificador cualificado con el espacio de nombres al que pertenece: (cualificaci´n expl´ o ıcita): NC::Complejo num. 5.fin: complejos.0). . (#include <cassert>) o o 11. ) { // captura cualquier excepcion throw. postcondiciones.. // lanza una excepcion . destruy´ndose todas las variables que han sido creadas en los u e a ´mbitos de los que se salga. si no es capaz de realizar su tarea y cumplir su postcondici´n. } catch ( .. Excepciones 11.. o o Una excepci´n es un mecanismo excepcional para manejar una situaci´n excepcional. } catch (const Error2 & var2) { // captura excepcion Error2 . ni es un o mecanismo para gestionar un error de programaci´n.Cap´ ıtulo 11 Manejo de errores. Si la ejecuci´n de un subprograma puede lanzar una excepci´n al programa llamante... throw Error1(args)..1.2. .. Se desactivan en c´digo de producci´n. Hacen referencia a precondiciones. } catch (const Error1 & var1) { // captura excepcion Error1 .. Son utiles durante el desarrollo y depuraci´n del ´ o programa... por lo tanto no deber´ formar parte del flujo de ejecuci´n normal de un programa.. o entonces lanzar´ una excepci´n. o Como norma general. Excepciones Las excepciones surgen como una forma de manejar situaciones de error excepcionales en los programas. invariantes. y as´ en este caso. Sin embargo.. o ı. Las precondiciones se pueden comprobar mediante assertos para a o ayudar en el desarrollo y depuraci´n. se puede o o indicar en la declaracion del subprograma indicando los tipos diferentes que se pueden lanzar 69 .. un subprograma (o m´todo) debe suponer que su precondici´n se cumple e o a su invocaci´n.. Asertos Los asertos (assert(cond)) comprueban que el programa sea consistente frente a errores de programaci´n.. etc. no es o o por lo tanto un mecanismo para controlar el flujo de ejecuci´n normal del programa. e La sintaxis es la siguiente: try { . No tiene sentido o su tratamiento... // relanza la misma excepcion } Cuando se lanza una excepci´n.. ıan o Son muy adecuadas porque permiten diferenciar el c´digo correspondiente a la resoluci´n del o o problema del c´digo encargado de manejar situaciones an´malas. un subprograma o o (o m´todo) puede comprobar las precondiciones mediante excepciones.. el control de ejecuci´n salta directamente al manejador que es o o capaz de capturarla seg´n su tipo. excepto abortar el programa. en Programaci´n Defensiva. . unsigned imayor(const vector<Tipo>& v) throw() { assert(true). } else { res = dividendo / divisor.size(). } return res. cout << division(x. int division(int dividendo. } Dpto. cin >> x >> y. return i.size()) || es_mayor(v[i]. v)). } int main() { try { int x.3.70 CAP´ ITULO 11. y) << endl. } catch ( . si el subprograma no lanza ninguna excepci´n. for (unsigned j = 1.. As´ mismo. se puede tambi´n ı o e indicar. } } 11. int divisor) throw(Error_Division_Por_Cero) { int res. } catch ( Error_Division_Por_Cero ) { cerr << "Division por cero" << endl. #include <iostream> using namespace std. EXCEPCIONES separados por comas. Ejemplos Ejemplo 1: si en el ´mbito de aplicaci´n es normal que haya vectores vac´ se puede utilizar a o ıos. ++j) { if (v[j] > v[i]) { i = j. } struct Error_Division_Por_Cero {}. int suma(int a. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . y despu´s comprobar el caso de que el vector fuese vac´ o e ıo. MANEJO DE ERRORES. j < v. unsigned i = 0. int b) throw() { return a + b. ) { cerr << "Error inesperado" << endl. y. } } assert((i >= v. la siguiente funci´n. if (divisor == 0) { throw Error_Division_Por_Cero(). ncols() > 0)). return m. a o Ejemplo 3: unsigned mayor(const vector<Tipo>& v) throw(Vector_Vacio) { assert(true).ncols() != a. unsigned mayor(const vector<Tipo>& v) throw() { assert(v.4. const Matriz& a.size() == 0) { throw Vector_Vacio(). EXCEPCIONES ESTANDARES 71 Ejemplo 2: se puede utilizar la siguiente funci´n si est´ garantizado que el vector no est´ vac´ o a a ıo. } } assert(es_mayor(m.4. . j < v. ++j) { if (v[j] > m) { m = v[j]. . } 11. } Ejemplo 3: si en el ´mbito de aplicaci´n.´ 11. Dpto.size() > 0). } // Algoritmo de Multiplicacion de Matrices assert(true).nfils()) { throw Error(). for (unsigned j = 1.size(). } Ejemplo 4: void mult(Matriz& c. se puede utilizar la siguiente funci´n. if (v. } } assert(es_mayor(m. El programa de o alguna forma deber´ proporcionar un manejador para el tratamiento de la posible excepci´n. lo normal es que no haya vectores vac´ aunque a o ıos. pudiera haberlos excepcionalmente. ++j) { if (v[j] > m) { m = v[j].nfils() > 0)&&(a. Excepciones est´ndares a Las excepciones que el sistema lanza est´n basadas en el tipo exception que se obtiene ina cluyendo el fichero <exception> y del cual podemos obtener un mensaje mediante la llamada a what(). const Matriz& b) throw(Error) { assert((a.ncols() > 0) &&(b.size(). Ejemplo: try { .nfils() > 0)&&(b. unsigned m = v[0]. o por alguna sentencia ıa o de control de flujo condicional. } unsigned m = v[0]. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Esta garant´ puede venir dada por el propio entorno de ejecuci´n. return m. v)). j < v. v)). if (a. for (unsigned j = 1. que pueden.. s´lo detectables cuando el programa se ejecuta y la unica alternativa es su o ´ manejo en tiempo de ejecuci´n. MANEJO DE ERRORES. } catch ( . invalid_argument(str). el sistema tiene un n´mero de excepciones predefinidas (derivadas del tipo exception ı u anterior). ser base para nuevas excepciones definidas por el programador (cap. #endif .2 Nota: para ver una t´cnica usual de programaci´n robusta respecto a la gesti´n de recursos en e o o un entorno con excepciones vease 17.. En versiones antiguas de GNUC. Son errores o predecibles..1. (#include <iostream>) Nota: para ver una descripci´n de los requisitos que deben cumplir las clases para comportarse o adecuadamente en un entorno de manejo de excepciones vease 13. (#include <stdexcept>) domain_error(str). a su vez. } As´ mismo. length_error(str). underflow_error(str) bad_alloc() lanzada en fallo en new (#include <new>) bad_cast() lanzada en fallo en dynamic_cast (#include <typeinfo>) bad_typeid() lanzada en fallo en typeid (#include <typeinfo>) bad_exception() lanzada en fallo en la especificacion de excepciones lanzadas por una funci´n. } Dpto.. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . 15): logic_error(str): especifican errores debidos a la l´gica interna del programa. (#include <stdexcept>) o range_error(str).what() << endl. out_of_range(str) runtime_error(str): errores debidos a eventos mas all´ del ´mbito del programa. overflow_error(str). ) { cout << "Error: Inesperado"<< endl. EXCEPCIONES } catch (const exception& e) { cout << "Error: " << e.72 CAP´ ITULO 11. (#include <exception>) o ios::failure() lanzada en fallo en operaciones de Entrada/Salida. detectables antes de que el programa se ejecute y por lo tanto evitables mediante chequeos adecuados en determinados lugares. se puede habilitar la caracter´ ıstica siguiente para hacer que la terminaci´n por causa de “excepci´n no capturada” muestre un mensaje de error: o o #include <exception> using namespace std. int main() { #ifdef __GNUC__ set_terminate (__gnu_cxx::__verbose_terminate_handler). Son erroa a res impredecibles. imag << ")" << endl. 73 . } void imprimir(char x) { cout << "caracter: " << x << endl. Nota: C++ no discierne entre un subprograma a u otro a partir del tipo del valor devuelto. double imag. void imprimir(int x) { cout << "entero: " << x << endl. }. Sobrecarga de subprogramas En C++ es posible definir diferentes subprogramas que posean el mismo nombre. #include <iostream> using namespace std. } void imprimir(double x) { cout << "real: " << x << endl. double imag) { cout << "complejo: (" << real << ". } void imprimir(const Complejo& cmp) { cout << "complejo: (" << cmp. } void imprimir(double real. y le sea posible al compilador discenir a entre ellos a partir de los par´metros en la llamada. " << imag << ")" << endl. siempre y cuando los par´metros asociados tengan diferentes tipos. struct Complejo { double real. " << cmp.Cap´ ıtulo 12 Sobrecarga de subprogramas y operadores 12.1.real << ". a izq. o o a Ejemplo: Dpto. a dcha. izq. asoc. asoc. nc.8). aridad. asoc. imprimir(5. . Los siguientes operadores no podr´n ser definidos: a :: . a dcha. izq. asoc.* & * / % + << >> < <= > >= == != & ^ | && || = += -= *= /= %= &= ^= |= <<= >>= . new new[] delete delete[] B U U B B B B B B B B B B B B U asoc. Sobrecarga de operadores No es posible definir nuevos operadores ni cambiar la sintaxis. dcha.2. dcha. dcha. imprimir(nc). a dcha. asoc. imprimir(5. izq. operator&.4. a dcha. izq. a dcha. a dcha. asoc.4. asoc. asoc.tipo() ! ~ + . 13). a dcha. operator. imprimir(’a’). izq. asoc. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . izq. La conversi´n de tipos s´lo podr´ definirse como funciones miembros de objetos (vease cap. izq. a dcha. nc. SOBRECARGA DE SUBPROGRAMAS Y OPERADORES int main() { Complejo nc. izq.74 } CAP´ ITULO 12. Se pueden definir el comportamiento de los siguientes operadores (siempre para tipos definidos por el programador): () [] -> ->* ++ -. asoc.6). aunque pueden ser redefinidos: operator=. a dcha. precedencia o asociatividad de los operadores existentes. //return 0. 13): operator=. operator[]. a dcha. asoc. a izq.imag = 2. a izq. izq. asoc. izq. asoc. a dcha. } 12. a dcha. 7. a dcha. izq. izq.real = 3. asoc. izq.* ?: sizeof typeid Los siguientes operadores s´lo podr´n definirse como funciones miembros de objetos (vease o a cap. operator(). asoc. operator-> Los siguientes operadores ya tienen un significado predefinido para cualquier tipo que se defina.3. imprimir(3). for (i = 0. return ant.ncar. return d.car[i]. } return res. } return sal. dest. d = (d == domingo) ? lunes : Dia(d+1). Dpto. bool operator == (const Cadena& c1. i < orig.car[i]. Dia& operator++(Dia& d) // prefijo { d = (d == domingo) ? lunes : Dia(d+1).car[i]). if (c1. martes. } Dia& operator++(Dia& d. ++i) { sal << cad.2. const Cadena& cad) { for (int i = 0. Lenguajes y Ciencias de la Computaci´n o 75 Universidad de M´laga a .ncar != c2. viernes. } const int MAX_CAD = 30. int) // postfijo { Dia ant = d. sabado. jueves. ++i) { // vacio } res = (i == c1. }.ncar) { res = false.12. for (i = 0.ncar).ncar. const Cadena& orig) // operator= { int i. miercoles. } ostream& operator << (ostream& sal.car[i] = orig. (i < c1. } Cadena& copiar (Cadena& dest. domingo }.ncar = orig. } else { int i. const Cadena c2) { bool res.car[i] == c2. } return dest. SOBRECARGA DE OPERADORES enum Dia { lunes. struct Cadena { int ncar. i < cad.ncar. // Maximo MAX_CAD-1 char car[MAX_CAD]. ++i) { dest.ncar)&&(c1. car. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .76 } CAP´ ITULO 12. } Dpto.car). cad.ncar = strlen(cad. SOBRECARGA DE SUBPROGRAMAS Y OPERADORES istream& operator >> (istream& ent. return ent. Cadena& cad) { ent >> setw(MAX_CAD) >> cad. public: class Fuera_de_Rango {}.Cap´ ıtulo 13 Tipos abstractos de datos Los tipos abstractos de datos dan la posibilidad al programador de definir nuevos tipos que se comporten de igual manera que los tipos predefinidos. a Vamos a realizar la definici´n e implementaci´n del tipo abstracto de datos “Cadena”. la forma en la que se crean y se destruyen. uint inicio = 0. // asignacion Cadena& operator=(const char orig[]) throw (Overflow). char _car[MAXIMO]. destruyen. Lo defio o niremos dentro del espacio de nombres bbl con el que identificaremos nuestra biblioteca. de tal forma que permiten definir su representaci´n interna. // destructor Cadena() throw(). // excepcion // excepcion ~Cadena() throw(). las operaciones que se pueden aplicar y las conversiones de tipos aplicables. De a esta forma se hace el lenguaje extensible. //. para que puedan ser manejadas correctamente. class Overflow {}. uint _longitud. uint ncar = MAXIMO) throw (Fuera_de_Rango. Adem´s. a indicaremos las posibles situaciones de error mediante excepciones. mediante la cual C++ posibilita la definici´n de nuevos tipos de datos que tengan asociao dos una representaci´n interna (atributos miembros) y unas operaciones (funciones miembros) que o se le apliquen. Overflow). // constructor Cadena(const Cadena& orig. uint inicio = 0. adem´s de poder definir la forma en la que se crean. uint ncar = MAXIMO) throw (Fuera_de_Rango. Para definir un tipo abstracto de datos utilizaremos un nuevo tipo de nuestro lenguaje: la clase (class). como se asignan y se pasan o como par´metros.fichero: cadena.hpp ------------------------------------------------#include <iostream> namespace bbl { class Cadena { private: typedef unsigned int uint.// ctor copia Cadena(const char orig[]. // ctor Cadena& operator=(const Cadena& orig) throw(). copian y asignan. Overflow). // asignacion 77 . static const uint MAXIMO = 256. const Cadena& c2) Cadena& c1. las declaraciones que la siguen adquieren un atributo de visibilidad dependiendo de la etiqueta especificada. una etiı. Cadena subcad(uint inicio = 0. const const const const Cadena& Cadena& Cadena& Cadena& c2). ser´ unica ı.78 CAP´ ITULO 13. friend std::istream& operator>> (std::istream& s. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .fin: cadena. A continuaci´n se declaran dos atributos variables para almacenar la longitud de la cadena o de un determinado objeto. } friend bool operator>= (const { return ! (c1 < c2). uint ncar = MAXIMO) const. Dentro de la zona privada definimos un nuevo tipo (uint) interno para simplificar la escritura del codigo. }. }// namespace bbl //. Cadena& cad) throw(Overflow). throw (Overflow). A los datos que componen un objeto les llamaremos atributos (miembros en terminolog´ ıa C++). ya que dicha modificaci´n (tanto para constantes como para variables) indica o que dicho atributo va a ser compartido por todas las instancias de la clase (objetos). c1. c1. TIPOS ABSTRACTOS DE DATOS const char& operator[] (uint i) const throw (Fuera_de_Rango). } friend bool operator> (const { return ! (c1 <= c2). c2) Cadena& c1. permitiendo as´ que diferentes objetos de la misma clase tengan atributos con valores ı diferentes. cada objeto que se declare de una determinada clase tendr´ diferentes instancias de los atributos a de la clase. uint longitud() const { return _longitud. As´ en nuestro caso de la constante est´tica MAXIMO. declaramos dos clases sin atributos ni funciones miembro. ser´n replicados para cada objeto que se declare de la clase y a a almacenar´n los diferentes valores de cada objeto. // conversion de tipo a natural operator uint() const { return longitud(). de tal forma que las declaraciones privadas s´lo podr´n ser o a accedidas y utilizadas en las funciones miembros de la clase que se est´ definiendo y las declaracioa nes p´blicas podr´n utilizarse por cualquier elemento que utilice alguna instancia de nuestra clase u a (objeto). const Cadena& cad). c1. a En la zona p´blica. c1.hpp ------------------------------------------------- As´ vemos en la declaraci´n de nuestra clase Cadena que hay dos zonas principales. al no ser est´ticos. Posteriormente declaramos el destructor de la clase mediante el s´ ımbolo ~ seguido del Dpto. y la otra para almacenar los caracteres que conforman la cadena. a a´ y compartida por todos los objetos. Es decir. } Cadena& operator+=(const Cadena& cad) Cadena& operator+=(const char cad[]) Cadena& operator+=(char car) friend bool operator== (const friend bool operator< (const friend bool operator<= (const friend bool operator!= (const { return ! (c1 == c2). const Cadena& c2) friend Cadena operator+ (const Cadena& c1. Dicha constante es necesaria que se declare modificada con la palabra o reservada static. throw (Overflow). } Cadena& Cadena& Cadena& Cadena& throw (Overflow). friend std::ostream& operator<< (std::ostream& s. Cada vez que se especifica una de dichas palabras reservadas. Son simplemente u dos definiciones de tipos que ser´n utiles a la hora de indicar los posibles errores mediante exa ´ cepciones. pero si alg´n atributo es de tipo static entonces dicho atributo ser´ unico y compartido u a´ por todos los objetos de la clase. }. c2). char& operator[] (uint i) throw (Fuera_de_Rango). c2). Estos atributos. o quetada con la palabra reservada private: y otra con public:. const Cadena& c2). As´ mismo definimos un atributo constante (MAXIMO) que ser´ visible s´lo en la impleı a o mentaci´n del TAD Cadena. As´ mismo. hemos definido el comportamiento o a de la funci´n en la propia declaraci´n. para definir como se realiza ´sta. El tipo destino puede ser cualquier tipo. Si el o constructor de copia no se define. Si no o o e se define este constructor. { Cadena c1. es una forma de evitar conversiones de tipo impl´ ıcitas. Dicho constructor se utiliza en las inicializaciones.. adem´s de o a poder utilizarse para obtener su valor como en char c = c1[3]. y adem´s. si queremos indicar que la funci´n no lanza ninguna excepci´n. Ambos devuelven una referencia a un elemento en vez de una copia de el. Hemos realizado dos declaraciones de este operador. no dando as´ ninguna informaci´n para su utilizaci´n. ya sea predefinido o definido por el usuario. De hecho. As´ mismo. en el paso por valor y al devolver un objeto una funci´n. En o o u esta declaraci´n especificamos que es una funci´n miembro const. As´ mismo. si a no se especifican en la llamada. hay dos especiales: el constructor por defecto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a ..79 identificador de la clase y una lista de par´metros vac´ (~Cadena(). se especificar´ una lista o o a de excepciones vacia. tambi´n hemos a ı e especificado las excepciones que puede lanzar la funci´n. de tal forma que el que utilice dicho o constructor est´ advertido de las excepiones que lanza. este hecho hace posible que el resultado de dicha funci´n o pueda aparecer en la parte izquierda de una asignaci´n. de evitar el paso por valor y la devoluci´n de un objeto por parte de una a o funci´n si se aplica al constructor de copia.. que no toma ning´n argumento y define como se crear´ un objeto de dicha clase si no se especifica u a ning´n valor. entonces se define uno autom´ticamente que realizar´ una copia a a individual de todos los atributos del objeto. Sin o ı o o embargo. Este destructor ser´ llamaa ıa a do autom´ticamente (y sin par´metros actuales) para una determinada instancia (objeto) de esta a a clase cuando el flujo de ejecuci´n del programa salga del ´mbito de visibilidad de dicho objeto. A continuaci´n se definen varias operaciones de concatenaci´n y despues se definen una serie de funciones o o Dpto. Respecto a este ultimo concepto. De hecho. o a Nota: un destructor nunca deber´ lanzar excepciones. o entonces se elimina la posibilidad de que el constructor se aplique de form´ impl´ a ıcita. este operador es fundamental a la hora de integrar el nuevo tipo definido dentro de aplicaciones que lo utilicen como si fuera un tipo predefinido. una para cuando se utiliza sobre un objeto constante y la otra cuando se utiliza sobre uno no constante. entonces el sistema define uno que realiza la asignaci´n de los atributos o del objeto. Vemos tambi´n que a ciertos par´teros les hemos e a asignado un valor (uint inicio = 0). Posteriormente declaramos el operador de indexaci´n []. } . a { . es decir. si no se especifica nada se considera u ´ que puede lanzar cualquier excepci´n. entonces tomar´n el valor indicado.. los constructores se utilizan tambi´n para conversiones de tipo ı e (tanto impl´ ıcitas como expl´ ıcitas) al nuevo tipo definido. que ser´ util a la hora de acceder a los o a´ elementos individuales de la cadena. Adem´s.. .). Posteriormente definimos como se realiza la conversion del tipo que estamos definiendo a otro tipo. de tal forma que son par´metros opcionales. } // construccion del objeto ’c1’ // utilizacion del objeto ’c1’ // destruccion del objeto ’c1’ A continuaci´n se declaran los constructores de la clase. o A continuaci´n declaramos el operador de asignaci´n. la ejecuci´n de dicha o o o funci´n no modifica al objeto sobre el que se aplica. tambi´n es util para que el e ı e ´ compilador compruebe la consistencia de dicha indicaci´n y muestre un mensaje de error si se lanzan o alg´n otro tipo de excepciones. y el constructor de copia que recibe como argumento un objeto de la misma clase u y define como crear un nuevo objeto que sea una copia del que se recibe. A continuaci´n declaramos una funci´n para saber el n´mero de caracteres de la cadena. es decir. Haciendo esto indicamos al compilador que queremos que o o dicha funci´n se traduzca “en l´ o ınea”. haciendo necesario que sea llamado expl´ ıcitamente. De entre todos ellos.. especificando as´ las diferentes formas o ı de crear un determinado objeto. Si se especifica la palabra reservada explicit delante de la declaraci´n de un constructor. por ejemplo c1[3] = ’U’. . zona privada al modulo inline unsigned minimo(unsigned x. Ejemplo: //.. //.hpp -------------------class X { static int cnt. e a Tambi´n es posible declarar atributos static que significa que el valor de dichos atributos es e compartido por todos los objetos de la clase. y de los atributos static const que hemos visto. public: ~X() {}. Adem´s de declarar los atributos normales. unsigned y) { return (x < y) ? x : y ... no ser´ necesario que se aplique a ning´n objeto especifico. que son funciones que no son funciones miembros del objeto que estamos definiendo. // . a se deber´ definir en el m´dulo de implementaci´n (cualificandolo con el nombre de la clase) y a o o asignarle un valor inicial. //. sino que son funciones que operan sobre los objetos que se especifican en los par´metros.hpp" int X::cnt = 0. dicho nuevo valor ser´ compartido por todos los objetos...80 CAP´ ITULO 13. } unsigned long_cstr(unsigned int max.cpp -------------------#include "x...cpp ------------------------------------------------#include <iostream> #include <iomanip> #include "cadena.hpp" using namespace std. //. As´ mismo.. }.fichero: cadena. de tal forma que si un objeto modifica su valor. const char cad[]) { unsigned i. es decir. // definicion e inicializacion del atributo estatico X::X() : //. TIPOS ABSTRACTOS DE DATOS friend. // lista de inicializacion // inicializacion Tambi´n es posible definir una funci´n miembro que sea static. namespace { // anonimo. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Al fina de las o declaraciones vemos las declaraciones de los operadores de entrada y salida. Dpto. a es posible definir atributos con el modificador mutable. a u //. que indicar´ que dicho atributo puede ser a modificado incluso por una funci´n const que indica que no modifica el objeto. } // . X().. Cuando se declara un atributo static. pueden acceder a la representaci´n interna del objeto. en cuyo caso se podr´ invocar e o a directamente sobre la clase. { ++cnt.fichero: x.fichero: x. dicho o ı atributo tambi´n podr´ ser modificado en un objeto constante. pero que a al ser friend de la clase. uint inicio. if (ultimo >= MAXIMO) { throw Overflow(). Overflow) : _longitud(0) { const uint orig_lng = long_cstr(MAXIMO+1. _longitud < ultimo. if ((inicio >= orig_lng)||(ncar == 0)) { throw Fuera_de_Rango(). if (ultimo >= MAXIMO) { throw Overflow(). (i < max) && (cad[i] != ’\0’). uint inicio.inicio). } for (_longitud = 0. uint ncar) throw (Fuera_de_Rango.81 for (i = 0. Overflow) : _longitud(0) { if ((inicio >= orig. _longitud < ultimo. orig_lng ._longitud)||(ncar == 0)) { throw Fuera_de_Rango(). } } Cadena::Cadena(const char orig[]. ++_longitud) { _car[_longitud] = orig[inicio + _longitud]. } }// namespace namespace bbl { Cadena::~Cadena() {} Cadena::Cadena() throw() : _longitud(0) {} Cadena::Cadena(const Cadena& orig. } const uint ultimo = minimo(ncar. } } Dpto. orig. uint ncar) throw (Fuera_de_Rango. ++_longitud) { _car[_longitud] = orig. ++i) { } return i._longitud .inicio). } const uint ultimo = minimo(ncar. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . } for (_longitud = 0._car[inicio + _longitud]. orig). * } */ /* * Referencia: Draft standard 2004/04/11 * section: 3. 3. using * explicit destruction followed by placement new. Consider how its correctness could depend on * whether operator=() was declared virtual in a base class or * not. * * But do these programmers really "know what they write"? Probably not. It’s almost always less efficient because construction * involves more work than assignment. * } * return *this. this * has the benefit of avoiding writing similar code in two places which * would then have to be maintained separately and could get out of sync * over time.82 CAP´ ITULO 13. TIPOS ABSTRACTOS DE DATOS Cadena& Cadena::operator= (const Cadena& orig) throw() { if (this != &orig) { // autoasignacion // destruir el valor antiguo y copiar el nuevo for (_longitud = 0. } /* * Cadena& * Cadena::operator= (const Cadena& orig) * { * if (this != &orig) { * Cadena aux(orig). for example by Dpto." * * Is there anything wrong with the original goal of improving * consistency? No. } } return *this. 2. This code even works in many cases.8 Object Lifetime (basic concepts 3-29) * * Nota en guru of the week [http://www. // destruccion automatica del valor anterior * } */ /* * Cadena& * Cadena::operator= (const Cadena& orig) * { * if (this != &orig) { * Cadena(orig)._car[_longitud]. I’m sometimes tempted to post the * above code in the office kitchen with the caption: "Here be dragons. It makes life a living hell for * the authors of derived classes. ++_longitud) { _car[_longitud] = orig. Here * are just four: 1. * since there are subtle pitfalls here. 4.swap(*this)._longitud.htm] * * These people mean well: the intent is to improve consistency by * implementing copy assignment in terms of copy construction.gotw. On the surface.ca/publications/advice97. _longitud < orig. but in this case "knowing what you write" would lead * the programmer to achieve consistency in a better way. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . some of them quite serious. // asignacion del valor sin perdida del anterior * } * return *this. // copia del valor * this->swap(aux). This code slices objects whenever *this and other * are not the same type. } return _car[i]. and shouldn’t encourage imitation. } if (orig[_longitud] != ’\0’) { throw Overflow(). That was to illustrate something * different. (Yes. } char& Cadena::operator[] (uint i) throw (Fuera_de_Rango) { if (i >= _longitud) { throw Fuera_de_Rango(). // destruccion del valor anterior * new (this) Cadena(orig). ++_longitud) { _car[_longitud] = orig[_longitud]. } return _car[i]. // copia del nuevo valor * } * return *this. inicio.83 * having a common private member function that does the work and is * called by both copy construction and copy assignment. I know * that an example like the above actually appears in the draft * standard. uint ncar) const { return Cadena(*this. } const char& Cadena::operator[] (uint i) const throw (Fuera_de_Rango) { if (i >= _longitud) { throw Fuera_de_Rango(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .) * * NO UTILIZAR -> NO FUNCIONA CORRECTAMENTE BAJO DETERMINADAS CIRCUNSTANCIAS * * Cadena& * Cadena::operator= (const Cadena& orig) * { * if (this != &orig) { * this->~Cadena(). } Dpto. Pretend it’s not there. (_longitud < MAXIMO)&&(orig[_longitud] != ’\0’). } return *this. ncar). } Cadena Cadena::subcad(uint inicio. * } */ Cadena& Cadena::operator= (const char orig[]) throw (Overflow) { // destruir el valor antiguo y copiar el nuevo for (_longitud = 0. } bool Dpto. } if (cad[i] != ’\0’) { throw Overflow(). } else { unsigned i. } return *this. for (i = 0. ++_longitud. } for (uint i = 0. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . ++i) { _car[_longitud] = cad[i]. TIPOS ABSTRACTOS DE DATOS Cadena& Cadena::operator+=(const Cadena& cad) throw (Overflow) { if (_longitud + cad._longitud != c2. ++i) { _car[_longitud] = cad. i < cad. } Cadena& Cadena::operator+=(const char cad[]) throw (Overflow) { uint i. } bool operator== (const Cadena& c1._car[i]). } return *this. for (i = 0._longitud._longitud)&&(c1. (_longitud < MAXIMO)&&(cad[i] != ’\0’). (i < c1._car[i] == c2. return *this._longitud > MAXIMO) { throw Overflow(). ++_longitud. const Cadena& c2) { bool res._longitud) { res = false. } Cadena& Cadena::operator+=(char car) throw (Overflow) { if (_longitud + 1 > MAXIMO) { throw Overflow().84 CAP´ ITULO 13._longitud)._car[i]. ++_longitud. if (c1. ++i) { // vacio } res = (i == c1. } return res. } _car[_longitud] = car. cpp ------------------------------------------------- En el m´dulo de implementaci´n de nuestro tipo abstracto de datos comienza con un espacio o o de nombres an´nimo con objeto de definir funciones privadas al m´dulo. y es una lista de inicializaciones separadas por comas que comienza con el s´ ımbolo :. res += c2. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . ++i) { // vacio } return (i == c1._longitud = strlen(cad. } return sal. for (i = 0. ++i) { sal << cad._longitud)&&(i < c2. dentro del espacio de nombres bbl.fin: cadena. const Cadena& c2) { unsigned i. cada nombre de funci´n se deber´ cualificar con el nombre de la o a clase a la que pertenece. Cadena& cad) throw(Cadena::Overflow) { ent >> setw(Cadena::MAXIMO) >> cad._longitud)&&(i < c2. As´ definimos el destructor de la clase para que no haga nada. i < cad._longitud) &&(c1. } bool operator< (const Cadena& c1. const Cadena& c2) { Cadena res = c1. } ostream& operator<< (ostream& sal.85 operator<= (const Cadena& c1. (i < c1. los constructores utilizando la lista de inicializaci´n de tal forma que llamamos individualmente a o los constructores de cada atributo de la clase (el orden debe coincidir con el orden en el que estan declarados). } }// namespace bbl //. } Cadena operator+ (const Cadena& c1._longitud)) ||((i < c1. return ent. Dpto._car)._car._longitud)&&(i < c2. o o Posteriormente._car[i]._longitud) &&(c1. const Cadena& cad) { for (unsigned i = 0._car[i] < c2._longitud._car[i]). return res. } istream& operator >> (istream& ent._car[i] == c2. for (i = 0._longitud)._car[i]))). (i < c1. Definimos ı._longitud)&&(i < c2. Para ello. ++i) { // vacio } return (((i == c1._longitud) &&(c1._car[i])._car[i] == c2. definimos las funciones miembro de la clase que estamos definiendo. const Cadena& c2) { unsigned i. cad. const Cadena c2 = "pepeluis". using namespace bbl. para posteriormente o copiar en nuevo objeto. "---------------------" << endl. podemos destruir el objeto antes de copiarlo. o Posteriormente. "|" << c3 << "|" << endl.hpp" using namespace std. Cadena c6(c3 . 3. cout cout cout cout cout cout cout cout cout << << << << << << << << << "---------------------" << endl. c3 = c1. "|" << c2 << "|" << endl.cpp ------------------------------------------------#include <iostream> #include "cadena. 5). o a Posteriormente implementamos cada funci´n definida en la clase. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . ya que no pertenecen a ella. "---------------------" << endl. Cadena c7("juanlucas". Cadena c3 = c2. al no ser funciones miembro. o ı ´ Estas. "---------------------" << endl. // ERROR "|" << c1 << "|" << endl. "|" << c6 << "|" << endl. // ERROR cout cout cout cout << << << << "|" << c1 << "|" << endl. "|" << c3 << "|" << endl. ya que si no lo evitamos.fichero: pr_cadena.subcad(2. "|" << c4 << "|" << endl. = ’U’. Al definir dicha operaci´n o o o o habr´ que tener en cuenta las siguientes consideraciones: Hay que comprobar y evitar que se a produzca una autoasignaci´n. Dpto. "|" << c1 << "|" << endl. deberemos destruir el antiguo valor del objeto receptor de la asignaci´n. "|" << c1[5] << "|" << endl. Cadena c5(c3 . a o A continuaci´n definimos como se realiza la operaci´n de asignaci´n. TIPOS ABSTRACTOS DE DATOS El cuerpo del constructor se encargar´ de terminar la construcci´n del objeto. esta funci´n deber´ devolver el objeto actual (*this). "|" << c2[5] << "|" << endl. cout << "|" << c4 << "|" << endl. "|" << c2 << "|" << endl. c1[5] = //c2[5] cout << cout << cout << cout << cout << c4 += c1. ’U’. as´ como las funciones friend.86 CAP´ ITULO 13. Cadena c4(c3). "|" << c2 << "|" << endl. //. int main() { try { Cadena c1. // c2 = c3. 2. y una vez que se ha comprobado que estamos asignando un objeto diferente. 2). c1 = "juanluis". no se cualifican con el nombre de la clase. "|" << c5 << "|" << endl. 5). "|" << c7 << "|" << endl. 3). 50).longitud(). M´todos definidos autom´ticamente por el compilae a dor El constructor por defecto (sin argumentos) ser´ definido automaticamente por el compilador a si el programador no define ning´n constructor.´ ´ 13.1. Cadena c8(c4.cpp ------------------------------------------------- 87 En el programa de prueba vemos una utilizaci´n del Tipo Abstracto de Datos donde se comprueo ba el normal funcionamiento de los objetos declarados de dicho tipo.fin: pr_cadena. vemos tambi´n como se crean los objetos de la clase utilizando a e diferentes constructores y diferente sintaxis. ++i) { c7 += "hasta overflow". cout << (c2 == c4) << endl. METODOS DEFINIDOS AUTOMATICAMENTE POR EL COMPILADOR cout << "|" << c4. for (int i = 0. 0). ) { cerr << "Excepcion inesperada" << endl. El comportamiento predefinido consistir´ en la llamada al a contructor de copia para cada atributo miembro de la clase. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . 13. cout << "|" << c4 + "pepe" << "|" << endl. Su comportamiento predefinido ser´ llamar al operador de a asignaci´n para cada atributo miembro de la clase.longitud() << "|" << endl.. cout << c4[50] << endl. Cadena c9(c4. El constructor por defecto de los tipos predefinidos es la inicializaci´n a cero. } } //. Dpto. El constructor de copia por defecto de los tipos predefinidos realizar´ una copia byte a byte de un objeto origen al objeto a destino. i < 50.. y su comportamiento predefinido ser´ llamar a los destructores de los atributos a miembros de la clase.subcad(2. Adem´s. El comportamiento predefinido consistir´ en u a la llamada al contructor por defecto para cada atributo miembro de la clase. El operador de asignaci´n por defecto o o de los tipos predefinidos realizar´ una asignaci´n byte a byte de un objeto origen al objeto a o destino. EL operador de asignaci´n ser´ definido autom´ticamente por el compilador si no es proo a a porcionado por el programador. el destructor de la clase se definir´ automaticamente por el compilador si no es definido por el a programador. o El constructor de copia se definir´ automaticamente por el compilador en caso de que el a programador no lo proporcione. } catch ( . c4[50] = ’Z’.1. cout << (c2 == c2) << endl. operaciones definidas en la clase sobre los objetos. } } catch (Cadena::Fuera_de_Rango) { cerr << "Excepcion: Indice fuera de rango" << endl. } catch (Cadena::Overflow) { cerr << "Excepcion: Overflow" << endl. e o 5) y en c4. As´ vemos como utilizar las ı. Los operadores se utilizan con la sintaxis esperada. 5. pero las funciones miembro se utilizan a trav´s de la notaci´n punto como en c1. // acceso a traves de puntero a miembro x.88 CAP´ ITULO 13. PointerToClaseXMemberAttr pma = &Clase_X::v. Antes de lanzar una excepci´n. por lo que debemos asegurarnos de liberar todos los recursos adquiridos durante la construcci´n fallida antes de lanzar la excepci´n o o (“adquisici´n de recursos es inicializaci´n”). struct Clase_X { int v. no se debe destruir la representaci´n antigua antes de haber o creado completamente la nueva representaci´n y pueda reemplazar a la antigua sin riesgo de o excepciones. o N´tese que un constructor es especial en que cuando lanza una excepci´n. o Antes de lanzar una excepci´n. Clase_X x. typedef int Clase_X::*PointerToClaseXMemberAttr. TIPOS ABSTRACTOS DE DATOS 13.*pmf)(). o o Cuando se lanza una excepci´n dentro de un constructor. Es decir. los recursos obtenidos dentro del cuerpo del o constructor deber´n liberarse si alguna excepci´n es lanzada. o 13. Utilizar la t´cnica “adquisici´n de recursos es inicializau e o ci´n” 17. Las operaciones de comparaci´n no deben lanzar excepciones.2. // llamada a traves de puntero a miembro Dpto. Sin embargo. Punteros a miembros Punteros a miembros de clases (atributos y m´todos). dejar cada objeto en un estado en el que pueda ser destruido por a su destructor de forma coherente y sin lanzar ninguna excepci´n.*pma = 3. typedef void (Clase_X::*PointerToClaseXMemberFunction) (). o Cuando se actualiza un objeto. N´tese los par´ntesis en la “llamada a e o e trav´s de puntero a miembro” por cuestiones de precedencia. se deber´ liberar todos los recursos adquiridos que no pero a tenezcan a ning´n otro objeto. e #include <iostream> using namespace std. Requisitos de las clases respecto a las excepciones Con objeto de dise˜ar clases que se comporten adecuadamente en su ´mbito de utilizaci´n es n a o conveniente seguir los siguientes consejos en su dise˜o: n No se deben lanzar excepciones desde los destructores.3. x. no deja ning´n o o u objeto “creado” para destruirse posteriormente. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .1. int main() { PointerToClaseXMemberFunction pmf = &Clase_X::miembro. // llamada directa a miembro (x. } }.miembro(). se deber´ asegurar de que cada operando se encuentra en un o a estado “v´lido”. se ejecutar´n los destructores o a asociados a los atributos que hayan sido previamente inicializados al llamar a sus constructores en la lista de inicializaci´n. void miembro() { cout << v << " " << this << endl. (“adquisici´n de recursos es a o o inicializaci´n”). // llamada a traves de puntero a miembro } Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . px->*pma = 5. // acceso a traves de puntero a miembro px->miembro(). // llamada directa a miembro (px->*pmf)().3.13. PUNTEROS A MIEMBROS 89 Clase_X* px = &x. TIPOS ABSTRACTOS DE DATOS Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .90 CAP´ ITULO 13. Tipo& y) { Tipo aux = x. Veamos un a a ejemplo de definiciones de funciones gen´ricas: e template <typename Tipo> inline Tipo maximo(Tipo x. definir clases y funciones de forma gen´rica que se instancien a tipos particulares en funci´n e o de la utilizaci´n de ´stas. } template <typename Tipo> void intercambio(Tipo& x. Tipo menor. 8). Tipo y) { return (x > y) ? x : y . y = aux. template<typename Tipo. intercambio(x. o e Los par´metros de las plantillas podr´n ser tanto tipos como valores constantes. Plantillas o e Las plantillas (“templates” en ingl´s) son utiles a la hora de realizar programaci´n gen´rica.hpp -------------------------------------------------#include <iostream> namespace bbl { template<typename Tipo. Tipo menor. Tipo mayor> 91 . y).Cap´ ıtulo 14 Programaci´n Gen´rica. se encontrar´n en los ficheros de definici´n. Tipo mayor> class Subrango. int y = maximo(x. a o Veamos otro ejemplo de una clase gen´rica: e //-fichero: subrango. } Estas definiciones gen´ricas. y e a o deber´n ser incluidos por todos aquellos m´dulos que las instancien. por regla general. } int main() { int x = 4. e ´ o e Esto es. x = y. mayor>::operator= (T_Base i) throw(Fuera_de_Rango) { if ((i < menor) || (i > mayor)) { throw Fuera_de_Rango(i). Tipo mayor> std::ostream& operator<<(std::ostream& sal. Tipo menor. PLANTILLAS std::ostream& operator<<(std::ostream&.menor. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Tipo menor. } template<typename Tipo. // return *this = Subrango(i). friend std::ostream& operator<< <>(std::ostream&. } } template<typename Tipo. const Subrango<Tipo._valor. mayor>&).menor. Tipo mayor> Subrango<Tipo.mayor>::Subrango(T_Base i) throw(Fuera_de_Rango) { if ((i < menor) || (i > mayor)) { throw Fuera_de_Rango(i).menor. } return *this. PROGRAMACION GENERICA. Subrango& operator= (T_Base i) throw(Fuera_de_Rango). operator T_Base() throw(). template<typename Tipo.92 ´ ´ CAP´ ITULO 14. // excepcion Subrango() throw(). const Subrango<Tipo. public: struct Fuera_de_Rango { T_Base val.mayor>::operator Tipo() throw() { Dpto. mayor>&). menor.menor. } else { _valor = i. Tipo mayor> Subrango<Tipo. } template<typename Tipo.menor. template<typename Tipo.mayor>::Subrango() throw() : _valor(menor) {} template<typename Tipo. } else { _valor = i. }. Tipo menor. Tipo mayor> Subrango<Tipo. menor.mayor>& i) { return sal << i. Tipo mayor> class Subrango { typedef Tipo T_Base. Tipo menor.mayor>& Subrango<Tipo. Tipo menor. Fuera_de_Rango(T_Base i) : val(i) {} }. Tipo mayor> Subrango<Tipo.const Subrango<Tipo. Tipo menor. Subrango(T_Base i) throw(Fuera_de_Rango).menor. T_Base _valor. y = 12. typedef Subrango<int. // definicion de la clase generica vacia template <typename _Key> struct hash { }. 15> int_10_15. 15>: " << fr. y = z. int main() { try { int_3_20 x.val << endl. 20>: " << fr.hpp ---------------------------------------------namespace __gnu_cxx { using std::size_t.cpp -------------------------------------------------- Veamos otro ejemplo de una definicion gen´rica (tomado de GCC 3. int z. 20> int_3_20.93 return _valor. int_10_15 y. ) { cerr << "Excepcion inesperada" << endl.hpp" #include <iostream> using namespace std.hpp -------------------------------------------------//-fichero: prueba. z = x. 3. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . } } // namespace bbl //-fin: subrango. //y = 20.cpp -------------------------------------------------#include "subrango. //x = 25. 3. } catch (int_3_20::Fuera_de_Rango& fr) { cerr << "Fuera de Rango<int.. } catch ( . } } //-fin: prueba. 10. inline size_t __stl_hash_string(const char* __s) { Dpto.val << endl. using namespace bbl. x = x + 5. 10. typedef Subrango<int. } catch (int_10_15::Fuera_de_Rango& fr) { cerr << "Fuera de Rango<int. x = 17. // fuera de rango // fuera de rango // fuera de rango // fuera de rango cout << x << endl..3) con especializaci´n: e o //-fichero: stl_hash_fun. *__s.hpp -------------------------------------------------- Una posible ventaja de hacer esta especializaci´n sobre un tipo que sobre una funci´n. } return size_t(__h). template<> struct hash<const char*> { size_t operator()(const char* __s) const { return __stl_hash_string(__s). es en tiempo de compilaci´n cuando falla. PROGRAMACION GENERICA. } // namespace __gnu_cxx //-fin: stl_hash_fun. ++__s) { __h = 5*__h + *__s. } }. } }. template<> struct hash<char> { size_t operator()(char __x) const { return __x. es que la o o funci´n estr´ definida para cualquier tipo. for ( . } }. a Dpto. y ser´ en tiempo de ejecuci´n donde rompa si se utiliza o a a o sobre un tipo no valido. } }. } }.94 ´ ´ CAP´ ITULO 14. PLANTILLAS unsigned long __h = 0. } // especializaciones template<> struct hash<char*> { size_t operator()(const char* __s) const { return __stl_hash_string(__s).c_str()). De esta forma. Otra ventaja es o que puede ser pasada coomo par´metro a un “template”. template <> struct hash<string> { size_t operator()(const string& str) const { return __stl_hash_string(str. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . template<> struct hash<int> { size_t operator()(int __x) const { return __x. Cap´ ıtulo 15 Programaci´n orientada a objetos o objetos La programaci´n Orientada a Objetos en C++ se fundamenta en el concepto de clases visto en o el cap´ ıtulo de Tipos Abstractos de Datos (cap. } int get_y() const { return _y. //Figura& operator= (const Figura& f) { _id = f. 13) junto al concepto de herencia y a los mecanismos que la soportan (funciones miembro virtuales y clases base abstractas). Veamos el siguiente ejemplo de una jerarqu´ de clases para representar objetos gr´ficos: ıa a //. } // D. } }.get_x() << ". } }._id._y. int _y.A.fichero: figuras._x. // accesible por las clases derivadas private: virtual void dibujar(std::ostream&) const = 0.hpp -----------------------------------------------#include <iostream> class Posicion { int _x. const Figura& fig) { fig. _y(y) {} int get_x() const { return _x._x). _p(f._id).A. int y = 0) : _id(id). Posicion(int x = 0. _y(p._p) {} // D. int x = 0. class Figura { protected: const char* _id. 95 . // virtual pura friend std::ostream& operator<<(std::ostream& sal. _p(x. } virtual Figura* clone() const = 0. } //Figura(const Figura& f) : _id(f. int y = 0) : _x(x). _p = f. " << _p. Figura(const char* id. y) {} virtual void mover(int x.dibujar(sal). return sal.get_y() << ") destruido" << std::endl. public: //~Posicion() {} // Definido Automaticamente por el compilador //Posicion(const Posicion& p) : _x(p. } // D. _y = p. int y) { _p = Posicion(x. // virtual pura public: virtual ~Figura() { std::cout << _id << " en Posicion(" << _p.A. Veamos estos nuevos conceptos que junto con los vistos en el cap´ ıtulo anterior respecto a las clases nos dar´n las herramientas que soporten el paradigma de la programaci´n orientada a objetos a o en C++._y) {} // Definido Automatica //Posicion& operator=(const Posicion& p) { _x = p._p. y). // accesible por las clases derivadas Posicion _p. _altura(a) {} virtual Rectangulo* clone() const { return new Rectangulo(*this). _altura = r._base. _base = r. _altura = t. El constructor de copia por defecto de los tipos predefinidos realizar´ una copia byte a byte de un a objeto origen al objeto destino. El comportamiento predefinido consistir´ en u a la llamada al contructor por defecto para las clases base y para cada atributo miembro de la clase. public: //virtual ~Rectangulo() {} //Rectangulo(const Rectangulo& r) // : Figura(r). EL operador de asignaci´n ser´ definido autom´ticamente por el compilador si no es proo a a porcionado por el programador. int _altura.hpp ------------------------------------------------ Nuestra definici´n de clases comienza con la definici´n de la clase Posicion que nos servir´ para o o a indicar la posici´n de una determinada figura en la pantalla. El comportamiento predefinido consistir´ en la llamada al a contructor de copia para las clases base y para cada atributo miembro de la clase. } }. public: //virtual ~Triangulo() {} //Triangulo(const Triangulo& t) // : Figura(t). de tal forma que s´lo el objeto podr´ acceder a ellas. } }._base)._altura. _altura(a) {} virtual Triangulo* clone() const { return new Triangulo(*this). y). y). } Rectangulo(int b. si el programador no los define. int x=0. A continuaci´n define los o a o m´todos p´blicos. el compilador autom´ticamente e u a define los siguientes con el comportamiento indicado: El constructor por defecto (sin argumentos) ser´ definido automaticamente por el compilador a si el programador no define ning´n constructor. El constructor por defecto de los tipos predefinidos es la inicializaci´n a cero. class Triangulo : public Figura { int _altura. x. b. class Cuadrado : public Rectangulo { public: //virtual ~Cuadrado() {} //Cuadrado(const Cuadrado& c) : Rectangulo(c) {} //Cuadrado& operator=(const Cuadrado& c) { Rectangulo::operator=(c) {} Cuadrado(int b._altura. int x=0. } Triangulo(int a. //. int y=0) : Figura("Triangulo". As´ define las coordenadas _x e _y o ı. int a. int x=0. x.fin: figuras. virtual void dibujar(std::ostream&) const. _altura(r. y) {} virtual Cuadrado* clone() const { return new Cuadrado(*this). int y=0) : Rectangulo(b. _altura(t. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . PROGRAMACION ORIENTADA A OBJETOS class Rectangulo : public Figura { int _base._altura) {} //Triangulo& operator=(const Triangulo& t) // { Figura::operator=(t). privadas a la clase._altura) {} //Rectangulo& operator=(const Rectangulo& r) // { Figura::operator=(r).96 ´ CAP´ ITULO 15. _base(b). _base(r. o El constructor de copia se definir´ automaticamente por el compilador en caso de que el a programador no lo proporcione. } }. Su comportamiento predefinido ser´ llamar al operador de a Dpto. int y=0) : Figura((a==b)?"Cuadrado":"Rectangulo". x. virtual void dibujar(std::ostream&) const. de los cuales. e Los m´todos virtuales son pieza clave en C++ para el soporte de la orientaci´n a objetos. deberemos definirlo nosotros. Su definici´n o se realiza en la lista de inicializaci´n inicializando los valores de los atributos _x e _y a los valores o especificados (debe coincidir con el orden de la declaraci´n). ı A continuaci´n definimos la clase Figura que hemos definido que sea una clase base abstracta. ya que cada clase debe definir como se construye y no es un concepto redefinible. hemos especificado que no lo tiene con = 0) indicamos que las clases derivadas deben definir el comprotamiento de dicho m´todo. El operador de o asignaci´n por defecto de los tipos predefinidos realizar´ una asignaci´n byte a byte de un o a o objeto origen al objeto destino. dicho comportamiento se vea reflejado correctamente. pero definimos su come portamiento. Es fundamental para el soporte del polimorfismo. al ser e o a a abstracta (en vez de definir su cuerpo. con lo que ser´ mas f´cil de mantener a a y cometeremos menos errores. Por lo tanto. no se podr´n definir objetos de dicha clase (ya que hay m´todos que no se implementan). Es o una “clase base” porque de ella derivar´n otras clases que hereden sus caracter´ a ısticas y proporciona un conjunto de m´todos com´nes a todas ellas. De esta forma. Igualmente sucede con el operador de asignaci´n. sino a que hemos definido el comportamiento que tendr´ dicho destructor. Adem´s. o Posteriormente definimos dos m´todos para acceder a los valores de la coordenada. y de todas las clases de las que hereda. que se define como virtual. sin cuerpo). y su comportamiento predefinido ser´ llamar a los destructores de las clases a base y de los atributos miembros. A continuaci´n declaramos un m´todo privado (s´lo ser´ accesible por m´todos de la propia o e o a e clase) virtual y abstracto (es decir. A continuaci´n se define el constructor de creaci´n que recibe las coordenadas de la posici´n (en o o o caso de que no se proporcionen se consideran los valores por defecto especificados). que inicializa los valores de sus atributos a trav´s de o e la lista de inicializaci´n. o con lo que indicamos que dichos atributos no son accesibles (son privados) por los usuarios de la clase. el destructor de la clase se definir´ automaticamente por el compilador si no es definido por a el programador. no es necesario definirlos. aunque se muestra como ser´ si el ıa programador la definiese). cuando ese es el comportamiento que queremos que tengan. las clases derivadas heredar´n dicho comportamiento. pero tambi´n a e podr´n redefinirlo para adaptar el comportamiento del m´todo. El comportamiento por defecto se encuentra definido simplemente como ejemplo. A continuaci´n definimos el constructor. a autom´ticamente se llaman a los destructores de su clase. Un m´todo ser´ abstracto e a cuando se declare con la siguiente sintax´ = 0 (adem´s de ser virtual). Cuando una clase base es ıs a abstracta. por lo que est´ tambi´n o a e comentado. y e que tras ser accedidos mediante el interfaz de la clase base. Cuando hay m´todos virtuales en una clase. Son funcioe nes miembro const ya que no modifican en s´ el objeto. de e o forma tal que permiten que las clases derivadas redefinan el comportamiento de tales m´todos. o e entonces el destructor siempre deber´ ser virtual. En la definici´n de la clase Figura hemos declarado dos miembros (_id y _p) como protected. pero sin embargo son accesibles para las clases derivadas. lo que le d´ esa caracter´ e a ıstica a toda la clase. a Posteriormente se comenta la definici´n del constructor de copia (que como es una copia de los o campos se prefiere la que define automaticamente el compilador. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . a e sino que ser´ necesario que se definan clases derivadas de ella que definan el comportamiento de a dichos m´todos. Al declararlo virtual estamos especificando que dicho m´todo podr´ ser definido por las clases derivadas. Los constructores nunca son virtuales. llamando a los constructores adecuados (en este caso al constructor de o la clase Posicion). en este caso no es abstracto. Posteriormente definimos el m´todo mover. ya que lo hace el propio compilador por nosotros. y que cuando se ejecuten dichos m´todos e a e a trav´s del interfaz proporcionado por la clase base. a e Dpto. Sin embargo. Es “abtracta” porque hemos declarado algunos e u m´todos abstractos. e A continuaci´n definimos el destructor de la clase. Cuando se destruye un objeto.97 asignaci´n para las clases base y para cada atributo miembro de la clase. dicha definici´n ser´ visible. En caso de necesitar otro comportamiento. get_x() << ". } sal << endl. j < _base. ı o o ni emplearse la asignaci´n. i < _altura. e inicializa el objeto base en la lista de inicializaci´n.cpp -----------------------------------------------#include "figuras. tampoco una funci´n debe devolver dicho objeto polim´rfico. es decir. En el definimos como se crea. " << _p. ´ste se pase por referencia. Dpto. As´ mismo. o e es decir. de tal forma que funcione perfectamente dentro de la herencia. for (int i = 0.cpp ------------------------------------------------ En el m´dulo de implementaci´n definimos aquellos m´todos que no han sido definidos en la o o e propia definici´n de clase (“en l´ o ınea”). ++i) { for (int j = 0." << endl.hpp" #include <iostream> using namespace std. } } void Triangulo::dibujar(ostream& sal) const { sal << _id << " en Posicion(" << _p.get_x() << ". j < 2*i+1. } for (int j = 0. ++i) { for (int j = 0. y lo definimos de tal forma que llame al m´todo e e (virtual) dibujar.98 ´ CAP´ ITULO 15. ++j) { sal << " " . void Rectangulo::dibujar(ostream& sal) const { sal << _id << " en Posicion(" << _p. e A continuaci´n definimos la clase Rectangulo para que sea una Figura con caracter´ o ısticas especiales. i < _altura. el mecanismo de soporte del polimorfismo no es soportado por el paso “por valor” de los argumentos a funciones. PROGRAMACION ORIENTADA A OBJETOS Para que el sistema de herencia funcione correctamente es necesario que cuando se pasa un objeto de una determinada clase a una funci´n. for (int i = 0." << endl. } } //. y llame a las funciones de redefinan dicho m´todo. Vemos como se definir´ tanto o ıan el constructor de copia como el operador de asignaci´n. " << _p.get_y() << "). j < _altura-i. ++j) { sal << "*" . o Definimos de igual forma la clase Cuadrado y la clase Triangulo.fichero: figuras. o Se declara tambi´n el m´todo clone como “virtual pura” de tal forma que cada objeto derivado e e sea capaz de copiarse a trav´s de este m´todo. ++j) { sal << "*" . definimos un rectangulo como una clase derivada de Figura.fin: figuras.get_y() << "). o un puntero al objeto. e e Despu´s declaramos el operador de salida. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . //. } sal << endl. 2. tales como convenciones. map. stack<tipo_base> st. 99 . Proporciona facilidades no primitivas sobre las cuales un programador se puede basar para portabilidad. tal como list. deque<tipo_base> dqu.1.Cap´ ıtulo 16 Biblioteca Est´ndar de C++. tal como sqrt y memmove. Caracter´ ısticas comunes Ficheros <vector> <list> <stack> <queue> <deque> <set> <map> <iterator> #include #include #include #include #include #include #include #include #include <utility> #include <functional> #include <algorithm> 16.1. Proporciona funciones que no se pueden implementar de forma ´ptima en el propio lenguaje o para cada sistema. tales como manejo de memoria y la informaci´n de tipo en tiempo de ejecuci´n. STL a La biblioteca est´ndar de C++ se define dentro del espacio de nombres std y: a Proporciona soporte para las caracter´ ısticas del lenguaje. entrada/salida.1. Contenedores // vector de tamano variable // lista doblemente enlazada // cola doblemente terminada // pila vector<tipo_base> vec. ordenaciones. tal o o como el valor del mayor float.1. Proporciona la base com´n para otras bibliotecas. etc. u 16. list<tipo_base> ls. 16. etc. o o Proporciona informaci´n sobre aspectos del lenguaje definidos por la implementaci´n. Proporciona un marco de trabajo para extender las facilidades que proporciona. i != nombre. Tipos definidos t::value_type // tipo del elemento t::allocator_type // tipo del manejador de memoria t::size_type // tipo de subindices. Operaciones de Pila y Cola // annade al final Universidad de M´laga a c.1. cuenta de elementos. // conjunto multiset<tipo_base> mcnj.back() v[i] v. it = ri + 1 for (list<tipo_base>::const_iterator i = nombre.front() c.end() c. STL queue<tipo_base> qu. ++i) { cout << *i. // cola priority_queue<tipo_base> pqu. // contenedor asociativo de pares de valores multimap<clave.rend() bi = back_inserter(contenedor) fi = front_inserter(conenedor) in = inserter(contenedor.valor> mp. t::difference_type // tipo diferencia entre iteradores t::iterator // iterador (se comporta como value_type*) t::const_iterator // iterador const (como const value_type*) t::reverse_iterator // iterador inverso (como value_type*) t::const_reverse_iterator// iterador inverso (como const value_type*) t::reference // value_type& t::const_reference // const value_type& t::key_type // tipo de la clave (solo contenedores asociativos) t::mapped_type // tipo del valor mapeado (solo cont asoc) t::key_compare // tipo de criterio de comparacion (solo cont asoc) 16.100 ´ CAP´ ITULO 16.base(). deque y map) elem de la posicion ’i’ => out_of_range (vector y deque) c. } contenedor<tipo_base>::iterator i = ri. // ri + 1 16. . BIBLIOTECA ESTANDAR DE C++.begin() c.1. Lenguajes y Ciencias de la Computaci´n o .4..rbegin() c.// cont asoc con repeticion de clave set<tipo_base> cnj.end().valor> mmp. iterador) it = ri. // cola ordenada map<clave. } for (list<tipo_base>::reverse_iterator i = nombre..3. i != nombre. // convierte de ri a it. Acceso // // // // primer elemento ultimo elemento elemento de la posicion ’i’ (vector.5.rend().1.1.// conjunto con valores multiples 16. Iteradores // // // // apunta apunta apunta apunta al al al al primer elemento (ultimo+1) elemento primer elemento (orden inverso) (ultimo+1) elemento (orden inverso) // insertador al final // insertador al principio // insertador en posicion c.begin().push_back(e) Dpto.6.base().at[i] 16.rbegin(). ++i) { *i = valor. splice(pos.11. CARACTER´ ISTICAS COMUNES c. l) // annade elementos [f:l) antes de p c.max_size() c. Constructores // // // // // contenedor vacio n elementos con valor por defecto (no cont asoc) n copias de x (no cont asoc) elementos iniciales copiados de [f:l) inicializacion igual a x cont() cont(n) cont(n.1. l) // elimina elementos [f:l) c.pop_front() // elimina el ultimo elemento // annade al principio (list y deque) // elimina el primer elemento (list y deque) 101 16. c. Asignaci´n o // copia los elementos de y a x // asigna n copias de x (no cont asoc) // asigna de [f:l) x = y.erase(f.1.size() c. x) c.sort(cmp2) // ordena segun bool cmp2(o1. x) cont(f.pop_back() c.assign(n. l) // mueve (sin copia) elementos [f:l) de lst a pos l. n.unique() // elimina duplicados adyacentes l.remove(v) // elimina elementos iguales a v l.remove_if(pred1) // elimina elementos que cumplen pred1 l.clear() // elimina todos los elementos // solo para list l. f. l) cont(x) 16. lst.find(k) m.size() == 0) tamano del mayor posible contenedor espacio alojado para el vector (solo vector) reservar espacio para expansion (solo vector) cambiar el tam del cont (solo vector.splice(pos.reserve(n) c.1.16. p) // mueve (sin copia) elemento posicion p de lst a pos l.1.10.capacity() c. x) // annade x antes de p c.9. Lenguajes y Ciencias de la Computaci´n o .resize(n) c.swap(y) == != < 16. cmp2) // mezcla ambas listas (ordenadas) en l l.8. Operaciones de Lista c.push_front(e) c. o2) l.insert(p.1. f.merge(lst) // mezcla ambas listas (ordenadas) en l l.splice(pos.unique(pred2) // elimina duplicados adyacentes que cumplen pred2 16. lst.lower_bound(k) Dpto.7.reverse() // invierte los elementos l.insert(p.merge(lst.assign(f. list y deque) intercambiar igualdad desigualdad menor c. lst) // mueve (sin copia) los elementos de lst a pos l.insert(p. Operaciones // // // // // // // // // // numero de elementos (c.empty() c.erase(p) // elimina elemento en p c. x) // annade n copias de x antes de p c. l) 16.1.sort() // ordena l. Operaciones Asociativas // acceder al elemento con clave k (para clave unica) // encontrar el elemento con clave k // encontrar el primer elemento con clave k Universidad de M´laga a m[k] m. | ++ -. e a proporcionando diferentes caracter´ ısticas.102 m.1.2.front op.value_comp() // // // // ´ CAP´ ITULO 16. STL encontrar el primer elem con clave mayor que k encontrar el lower_bound(k) y upper_bound(k) copia la clave copia el valor 16.list op. // vector de enteros de tamano inicial vacio vect_int v2(100).3. #include <vector> Construcci´n: o typedef std::vector<int> vect_int. // vector de 100 elementos con valor inicial por defecto Dpto.back iter -----------------------------------------------------------------vector const O(n)+ const+ Random list const const const Bidir deque const O(n) const const Random -----------------------------------------------------------------stack const queue const const prque O(log(n)) O(log(n)) -----------------------------------------------------------------map O(log(n)) O(log(n))+ Bidir mmap O(log(n))+ Bidir set O(log(n))+ Bidir mset O(log(n))+ Bidir -----------------------------------------------------------------string const O(n)+ O(n)+ const+ Random array const Random valarray const Random bitset const ------------------------------------------------------------------ 16.upper_bound(k) m.13. Proporciona. Resumen [] op.+ .12. as´ mismo. ı iteradores aleatorios. vector Es una secuencia optimizada para el acceso aleatorio a los elementos.equal_range(k) m. Contenedores Los contenedores proporcionan un m´todo est´ndar para almacenar y acceder a elementos.+= -= Comparac | | == != | == != | == != | == != < > >= <= ------------+-------+-------+-------+-------+---------------------- 16. Operaciones sobre Iteradores |Salida |Entrada|Avance |Bidir |Random ------------+-------+-------+-------+-------+---------------------Leer | | =*p | =*p | =*p | =*p Acceso | | -> | -> | -> | -> [] Escribir | *p= | | *p= | *p= | *p= Iteracion | ++ | ++ | ++ | ++ -.key_comp() m. vect_int v1. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . 16.1. BIBLIOTECA ESTANDAR DE C++. at(i). dev it al elem (crece) v1.size() == 0) Tama˜o del contenedor: n n = v1.insert(it_pos. val_inicial). it_fin).3. // vector de elementos copia de [it_ini:it_fin[ vect_int v5(v4). typedef std::vector<Fila> Matriz. it_i. // inserta val en posicion.push_back(val). Matriz m(100. // acceso al elemento i-esimo (lanza out_of_range si no existe) Operaciones de Pila v1. it_f). dev it al sig (decrece) it = v1. it_f). // acceso al primer elemento (debe existir) cout << v1. // acceso al ultimo elemento (debe existir) // acceso al ultimo elemento (debe existir) Acceso aleatorio a elementos (s´lo vector y deque): o cout << v1[i].front(). // inserta [it_i:it_f[ en pos (crece) it = v1. // asignacion de 50 elementos con val_inicial Acceso a elementos: cout << v1. // elim elems en [it_i:it_f[. // elimina el ultimo elemento (decrece) (no devuelve nada) Operaciones de Lista it = v1. // acceso al elemento i-esimo (lanza out_of_range si no existe) v1.insert(it_pos. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .assign(it_ini. // acceso al elemento i-esimo (debe existir) cout << v1. // asignacion de los elementos [it_ini:it_fin[ v1. // acceso al elemento i-esimo (debe existir) v1[i] = 3. // Matriz de 100 filas X 50 columnas Asignaci´n (despu´s de la asignaci´n. // vector copia de v4 typedef std::vector<int> Fila.at(i) = 3. val_inicial).16. Fila(50)). dev it al sig (decrece) v1.assign(50.insert(it_pos. VECTOR 103 vect_int v3(50. // elimina elem en pos. // inserta n copias de val en posicion (crece) v1. // annade val al final de v1 (crece) v1.back() = 1.erase(it_pos). // (v1. // numero de elementos de v1 bool b = v1. // vector de 50 elementos con el valor especificado vect_int v4(it_ini.clear(). el tama˜o del vector asignado se adapta al n´mero de o e o n u elementos asignados): //(se destruye el valor anterior de v1) v1 = v2.size(). // redimensiona el vector al nuevo_tam con valor por defecto Dpto. (decrece) (no devuelve memoria) N´mero de elementos: u n = v1.empty(). v1. // elimina todos los elementos. // asignacion de los elementos de v2 a v1 v1.erase(it_i.front() = 1.pop_back(). val). // tamanno del mayor vector posible // solo vector deque list v1. // acceso al primer elemento (debe existir) v1.back().max_size().resize(nuevo_tam). it_fin). val). n. // solo vector v1. Proporciona. v1 != v2 .swap(aux).capacity(). // se devuelve la memoria anterior de vect } 16.resize(nuevo_tam. // se devuelve la memoria anterior de vect } template <typename Tipo> void reajustar_vector(std::vector<Tipo>& vect) { std::vector<Tipo> aux(vect). val_inicial). swap(v1 . vect. el tama˜o de la lista asignada se adapta al n´mero de o e o n u elementos asignados): //(se destruye el valor anterior de l1) l1 = l2. val_inicial).assign(50. v1 >= v2 v1.104 ´ CAP´ ITULO 16. template <typename Tipo> void vaciar_vector(std::vector<Tipo>& vect) { std::vector<Tipo> aux. utiliza valor. // lista de enteros de tamano inicial vacio l2(100). v1 > v2 . list Es una secuencia optimizada para la inserci´n y eliminaci´n de elementos. BIBLIOTECA ESTANDAR DE C++. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . // redimensiona el vector.swap(v2). as´ miso o ı mo. v2).assign(it_ini. // asignacion de 50 elementos con val_inicial Acceso a elementos: Dpto. // asignacion de los elementos de l2 a l1 l1. it_fin).reserve(n). // lista de 100 elementos con valor inicial por defecto l3(50. // Se garantiza que la memoria es contigua // aunque puede ser realojada por necesidades de nuevo espacio Otras operaciones: v1 == v2 . valor).4. // asignacion de los elementos [it_ini:it_fin[ l1. // reservar n elementos (prealojados) sin inicializar valores n = v1. v1 < v2 . // numero de elementos reservados assert(&v[0] + n == &v[n]). list_int list_int list_int list_int list_int l1. #include <list> Construcci´n: o typedef std::list<int> list_int. v1 <= v2 . iteradores bidireccionales. // lista copia de l4 Asignaci´n (despu´s de la asignaci´n. vect. // lista de 50 elementos con el valor especificado l4(it_ini. STL v1. // lista de elementos copia de [it_ini:it_fin[ l5(l4). it_fin).swap(aux). it_f).size() == 0) Tama˜o del contenedor: n n = l1. dev it al elem (crece) l1. utiliza valor. // invierte los elementos de l1 l1. // tamanno de la mayor lista posible // solo vector deque list l1. (decrece) N´mero de elementos: u n = l1.clear().insert(it_pos. it_f).insert(it_pos. Otras operaciones propias del contenedor lista: l1. // elimina todos los elementos.empty().erase(it_pos). // acceso al primer elemento (debe existir) cout << l1. it_f). swap(l1 .front() = 1.reverse().sort(cmp2).front(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . // ordena l1 segun bool cmp2(e1. valor). dev it al sig (decrece) l1. l1 != l2 . // inserta [it_i:it_f[ en pos (crece) it = l1. dev it al sig (decrece) it = l1.splice(it_pos. // elimina elem en pos. // annade val al principio de l1 (crece) l1.size(). // mueve (sin copia) [it_i:it_f[ de l2 a pos l1. // (l1. l1 > l2 . // inserta n copias de val en posicion (crece) l1.erase(it_i.remove(val).16.max_size().splice(it_pos.pop_front(). l1 <= l2 . // numero de elementos de l1 bool b = l1. // elimina de l1 todos los elementos igual a val l1.splice(it_pos. val). e2) Dpto. // ordena l1 l1. // elim elems en [it_i:it_f[.pop_back(). // redimensiona la lista.resize(nuevo_tam).push_back(val). // acceso al ultimo elemento (debe existir) // acceso al ultimo elemento (debe existir) 105 Operaciones de Pila l1. // mueve (sin copia) (*it_el) de l2 a pos l1.sort(). l2. // elimina el primer elemento (decrece) (no devuelve nada) Operaciones de Lista it = l1. n. l1 >= l2 l1.insert(it_pos. LIST cout << l1. // redimensiona la lista al nuevo_tam con valor por defecto l1. // elimina el ultimo elemento (decrece) (no devuelve nada) Operaciones de Cola (solo list y deque) l1. // acceso al primer elemento (debe existir) l1.4. val). // annade val al final de l1 (crece) l1. l1 < l2 . // mueve (sin copia) los elementos de l2 a pos l1.remove_if(pred1).back() = 1. l2. // elimina de l1 todos los elementos que cumplen pred1(elem) l1.push_front(val). l2). it_el). // inserta val en posicion.back(). Otras operaciones: l1 == l2 . l1. l2).swap(l2). it_i. it_i.resize(nuevo_tam. e2) l1. .unique(pred2). public: mayor_que(int val) : _valor(val) {} // constructor bool operator() (int elem) const { return (elem > _valor). // mezcla ambas listas (ordenadas) en l1 segun cmp2(e1. 3)).remove_if(mayor_que_5). } Veamos otro ejemplo: bool mayor1(const string& s1. // elimina elementos adyacentes que cumplen pred2(e1. } }. cmp2).unique().remove_if(mayor_que(3)). l1. // mezcla ambas listas (ordenadas) en l1 (mueve sin copia) l1. } o tambi´n de la siguiente forma: e int main() { std::list<int> l1. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . l1. o Ejemplo: bool mayor_que_5(int elem) { return (elem > 5). } bool operator()(const Tipo& arg1. BIBLIOTECA ESTANDAR DE C++.remove_if(bind2nd(greater<int>().merge(l2. e2) Tanto los predicados como las funciones de comparaci´n pueden ser funciones (unarias o o binarias) que reciben los argumentos (1 o 2) del tipo del elemento del contenedor y devuelven un bool resultado de la funci´n. const string& s2) { Dpto. l1. l1. 5)). const Tipo& arg2) {} o tambi´n de la siguiente forma: e class mayor_que : public unary_function<int. bool> { int _valor. . // elimina elementos duplicados adyacentes l1. STL l1.remove_if(bind2nd(greater<int>(). .merge(l2). } int main() { .remove_if(mayor_que(5)). . .106 ´ CAP´ ITULO 16. . o un objeto de una clase que tenga el operador () definido. . l1. . int main() { std::list<int> l1. } }. #include <deque> Construcci´n: o typedef std::deque<int> deq_int.assign(50. // acceso al ultimo elemento (debe existir) // acceso al ultimo elemento (debe existir) Acceso aleatorio a elementos (s´lo vector y deque): o cout << d1[i].sort().at(i). l1.sort(mayor2()). . string.sort(mayor1). } // // // // ordena ordena ordena ordena de de de de menor mayor mayor mayor a a a a mayor menor (utiliza mayor1) menor (utiliza mayor2()) menor (utiliza greater<>()) 16. it_fin). it_fin). // deque de enteros de tamano inicial vacio d2(100). } 107 class mayor2 : public binary_function<string. // asignacion de los elementos [it_ini:it_fin[ d1.16.front().back() = 1. // deque de 100 elementos con valor inicial por defecto d3(50. // asignacion de 50 elementos con val_inicial Acceso a elementos: cout << d1. // acceso al elemento i-esimo (debe existir) cout << d1. deq_int deq_int deq_int deq_int deq_int d1. // deque de elementos copia de [it_ini:it_fin[ d5(d4).5. d1. // acceso al elemento i-esimo (lanza out_of_range si no existe) Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . DEQUE return s1 > s2. int main() { std::list<string> l1. l1. val_inicial). . val_inicial).assign(it_ini. deque Secuencia optimizada para que las operaciones de inserci´n y borrado en ambos extremos sean o tan eficientes como en una lista. Proporciona iteradores aleatorios. bool> { public: bool operator() (const string& s1. // asignacion de los elementos de d2 a d1 d1. // acceso al elemento i-esimo (debe existir) d1[i] = 3. // acceso al elemento i-esimo (lanza out_of_range si no existe) d1. // acceso al primer elemento (debe existir) d1. l1. y el acceso aleatorio tan eficiente como un vector. // acceso al primer elemento (debe existir) cout << d1.back(). // deque copia de d4 Asignaci´n (despu´s de la asignaci´n.at(i) = 3. const string& s2) const { return s1 > s2. // deque de 50 elementos con el valor especificado d4(it_ini.front() = 1. el tama˜o del deque asignado se adapta al n´mero de o e o n u elementos asignados): //(se destruye el valor anterior de d1) d1 = d2. l1. .5.sort(greater<string>()). empty().size().resize(nuevo_tam). // inserta n copias de val en posicion (crece) d1. d1 < d2 . it_f). // redimensiona el deque. if (p1. val). int main() { pila_c p1.push(’a’). // elimina todos los elementos. stack Proporciona el “Tipo Abstracto de Datos Pila”.push(’b’). it_i. // elim elems en [it_i:it_f[. d2). dev it al elem (crece) d1. // inserta val en posicion. STL d1.insert(it_pos. val).push(’c’). utiliza valor.108 Operaciones de Pila ´ CAP´ ITULO 16. 16. (decrece) N´mero de elementos: u n = d1.resize(nuevo_tam. p1. d1 != d2 . // elimina el primer elemento (decrece) (no devuelve nada) Operaciones de Lista it = d1. dev it al sig (decrece) it = d1. it_f).6. valor).push_back(val). No proporciona iteradores. // tamanno del mayor deque posible // solo vector deque list d1.pop_front().swap(d2). Otras operaciones: d1 == d2 . p1. // inserta [it_i:it_f[ en pos (crece) it = d1. n. d1 >= d2 d1. // annade val al final de d1 (crece) d1.insert(it_pos.pop_back(). // numero de elementos de d1 bool b = d1.clear(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a // [] // [a] // [a b] // [a b c] .push_front(val).max_size(). // (d1. dev it al sig (decrece) d1. d1 > d2 . y se implementa sobre un deque. d1 <= d2 . #include <stack> typedef std::stack<char> pila_c. p1. // annade val al principio de d1 (crece) d1. // elimina elem en pos. // redimensiona el deque al nuevo_tam con valor por defecto d1.insert(it_pos.size() != 3) { Dpto.size() == 0) Tama˜o del contenedor: n n = d1. BIBLIOTECA ESTANDAR DE C++.erase(it_i. swap(d1 . // elimina el ultimo elemento (decrece) (no devuelve nada) Operaciones de Cola (solo list y deque) d1.erase(it_pos). 7. No proporciona iteradores. if (c1. p1. y se implementa sobre un deque.push(’b’). QUEUE // imposible } if (p1.pop(). int main() { cola_c c1. p1.size() != 3) { // imposible } if (c1.push(’a’). if (! p1.pop().7.front() != ’a’) { // imposible } c1.16. if (p1.back() != ’c’) { // imposible } if (c1.pop(). if (c1. Dpto.push(’c’). c1.front() = ’A’. c1.size() != 3) { // imposible } p1. Lenguajes y Ciencias de la Computaci´n o // [] // [a] // [a b] // [a b c] // [A b c] // // [b c] [c] Universidad de M´laga a .pop().top() != ’c’) { // imposible } p1. #include <queue> typedef std::queue<char> cola_c. c1.pop().empty()) { // imposible } } // [a b] // [a] // [] 109 // [a b C] 16.top() = ’C’. c1.size() != 3) { // imposible } c1. queue Proporciona el “Tipo Abstracto de Datos Cola”. valor> optimizada para el acceso r´pido basado en clave. c1. y se implementa sobre un vector. if (! c1. map Secuencia de pares <clave.size() != 4) { // imposible } if (c1. Dpto. //typedef std::priority_queue< int. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .9. std::less<std::string> > map_str_int. No proporciona iteradores.empty()) { // imposible } } ´ CAP´ ITULO 16.push(5). c1. if (c1. c1.pop().pop(). ´ #include <map> //#include <functional> //typedef std::map< std::string. STL // [] 16.110 c1. std::less<int> > pcola_i. Clave a unica. BIBLIOTECA ESTANDAR DE C++. c1.8.top() != 7) { // imposible } c1.pop().push(4). c1. c1.empty()) { // imposible } } // // // // [5 4 3] [4 3] [3] [] // [] // // // // [5] [5 3] [7 5 3] [7 5 4 3] 16. typedef std::priority_queue<int> pcola_i. // ordenacion < int main() { pcola_i c1.push(7).pop(). Proporciona iteradores bidireccionales. #include <queue> //#include <functional> using namespace std.push(3). int.pop(). std::vector<int>. priority-queue Proporciona el “Tipo Abstracto de Datos Cola con Prioridad”. c1. if (! c1. it_fin). MULTIMAP typedef std::map<std::string. n = m1.max_size().empty().16. std::less<std::string> > mmap_str_int.swap(m2). // primer elemento con clave mayor que "pepe" Dpto.size(). devuelve 3 asigna nuevo valor 111 it = m1.insert(it_pos. // encontrar el elemento con una determinada clave int n = m1. s). // primer elemento con clave "pepe" it = m1.equal_range("pepe").find("pepe"). it = m1. #include <map> //#include <functional> //typedef std::multimap< std::string. // cuenta el numero de elementos con clave "pepe" it = m1.swap(m2). bool> p = m1. map_str_int m1. n = m1. p. devuelve 0. typedefstd:: multimap<std::string. // // // // crea nueva entrada.count("pepe"). pair<it.upper_bound("pepe"). int. crea nueva entrada a 0 y le asigna 3. it = m1.10. multimap Secuencia de pares <clave.erase(it_pos). valor> optimizada para el acceso r´pido basado en clave. bool b = m1.insert(it_ini. m1.erase(it_ini. it_fin).lower_bound("pepe").10.erase(clave). Permite a claves duplicadas.clear(). m1. m1["pepe"] = 4. m1["juan"] = 3.max_size(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .find("pepe"). int> map_str_int.lower_bound("pepe").upper_bound("pepe"). Proporciona iteradores bidireccionales.size(). int x = m1["pepe"]. mmap_str_int m1. valor = it->second.empty(). valor> p = make_pair(f. m1. m1. // rango de elementos con clave "pepe" clave = it->first. val)). val)). n = m1. bool b = m1. make_pair(clave. int y = m1["juan"].count("pepe").first // clave p. // primer elemento con clave "pepe" it = m1. m1. int> mmap_str_int.it> pit = m1. #include <utility> pair<clave. m1. // encontrar el elemento con una determinada clave int n = m1.second // valor 16. // cuenta el numero de elementos con clave "pepe" it = m1. int n = m1. n = m1.insert(make_pair(clave. // primer elemento con clave mayor que "pepe" pair<it. // primer elemento con clave "pepe" it = s1. it_fin). elem). tipo2> p = std::make_pair(f.clear().size().insert(it_pos. p. m1. Proporciona iteradores bidireccionales. valor> p = std::make_pair(f.12.erase(clave). m1. #include <utility> std::pair<tipo1.count("pepe"). std::less<std::string> > set_str. pero permite elementos duplicados.first p. #include <utility> std::pair<clave. val)). // rango de elementos con clave "pepe" it = m1.lower_bound("pepe").second 16. // primer elemento con clave mayor que "pepe" pair<it. set_str s1. val)).insert(it_pos. bool> p = s1.insert(it_ini. set Como un map donde los valores no importan. s1. // encontrar el elemento con una determinada clave int n = s1.insert(make_pair(clave. #include <set> //#include <functional> //typedef std::set< std::string. bool b = s1.it> pit = m1. s1. // rango de elementos con clave "pepe" pair<it. // cuenta el numero de elementos con clave "pepe" it = s1. STL pair<it.erase(it_ini. it = m1.equal_range("pepe").upper_bound("pepe"). s). int n = m1. s1. multiset Como set. make_pair(clave. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . n = s1. it_fin).11.erase(clave).clear().insert(elem).it> pit = s1. it_fin).insert(it_ini. n = s1.erase(it_ini. s1. Proporciona iteradores bidireccionales. m1. s1. solo aparecen las claves.112 ´ CAP´ ITULO 16.empty().erase(it_pos). int n = s1. #include <set> //#include <functional> Dpto. p. typedef std::set<std::string> set_str. m1. s).max_size().swap(s2).find("pepe").second // valor 16.erase(it_pos).equal_range("pepe"). it_fin). BIBLIOTECA ESTANDAR DE C++. it = s1.first // clave p. it = s1. it = s1. // rango de elementos con clave "pepe" it = s1. // 0000000000000110 m3. // 0000000000100010 m2. // m3 = m3 & m2.set(). #include <bitset> typedef std::bitset<16> mask.swap(s2). // cuenta el numero de elementos con clave "pepe" it = s1.erase(it_ini.second 16.it> pit = s1. // 0000000000000010 m4. s1.first p.insert(it_ini.13. // m3 = m3 | m2. tipo2> p = std::make_pair(f. s1.13. s1. // xor mask m4 = "0100000000110100". // 16 bits todos a 0 mask m2 = 0xaa. elem). bitset Un bitset<N> es un array de N bits.count("pepe"). n = s1.equal_range("pepe"). // m3 = m3 ^ m2. s). // encontrar el elemento con una determinada clave int n = s1. p.erase(clave). it_fin). BITSET 113 //typedef std::multiset< std::string.empty(). s1.clear(). typedef std::multiset<std::string> mset_str. // or m3 ^= m2. // 0000000000000000 m4.set(2.reset(5). // 0000000000110100 m3[2] == 1.set(5). // primer elemento con clave mayor que "pepe" pair<it. // 0000000010101010 mask m3 = "110100". s1. // 1111111111111101 Dpto.erase(it_pos). // and m3 |= m2. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .find("pepe"). mask m1.upper_bound("pepe").lower_bound("pepe").insert(it_pos. int n = s1.size(). // primer elemento con clave "pepe" it = s1. std::less<std::string> > mset_str. m4 <<= 2.max_size(). 0). it_fin). // 0000000011010000 m4 >>= 5.reset(). // 0000000000100110 m4. // 1111111111111111 m4.flip(). m3 &= m2. n = s1.insert(elem). #include <utility> std::pair<tipo1.16. bool b = s1. it = s1. mset_str s1. 14. BIBLIOTECA ESTANDAR DE C++.flip(3).test(3). 2 . // bool b = m1. las siguientes operaciones: Obtener el objeto asociado al iterador *it it->campo it->miembro() Moverse al siguiente elemento de la secuencia ++it (-.any(). const int MAX = 10.count(). 8 . proporcionando una o visi´n abstracta de los datos de forma que un determinado algortimo sea independiente de los o detalles concernientes a las estructuras de datos.end(). std::string str = m1.count() == 0) (m1[3] == 1) std::cout << m1 << std::endl. 3 . ´ CAP´ ITULO 16. Iteradores Proporcionan el nexo de uni´n entre los contenedores y los algoritmos. 7 .end(). directos typedef std::vector<int> vect_int. typedef vect_int::iterator vi_it. typedef vect_int::const_iterator vi_cit. 16. entre otras.+ . vi_it inicio_secuencia = vi. n) Comparaci´n entre iteradores o == != (< <= > >=) #include <iterator> n = distance(first.15.none(). 9 } vi_cit inicio_secuencia_const = vi. // bool b = m1.to_ulong().end(). i != vi. int n = 0. for (vi_it i = vi. o Los iteradores proporcionan. 6 .to_string().begin().114 m4. ++i) { *i = n.begin(). int n = m1. } // vi = { 0 . last) 16. Los iteradores proporcionan la visi´n de los contenedores como secuencias de objetos. vi_it fin_secuencia = vi. vi_cit fin_secuencia_const = vi.count() > 0) (m1.begin(). 1 . vect_int vi(MAX). unsigned long val = m1. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . STL // 1111111111110101 m1 = ~(m4 << 3). Dpto. 4 . 5 . // bool b = m1. ++n.// numero de bits numero de bits a 1 (m1. // int n = m1.+= -=) advance(it.size(). ++n. typename RIT> inline void reverse_to_direct(IT& it. vi_rit inicio_secuencia_inversa = vi.. // error. 1 . i != vi. vi_rit fin_secuencia_inversa = vi.. cout << *i } // 0 1 2 3 4 5 = vi.16. 8 . vect_int::iterator vi_it. ++i) { *i = n. --it.rbegin(). for (MapStrUint::const_iterator it = mapa. vect_int vi(MAX). 3 . } 16.begin().rend(). 6 .end(). } Un puntero a un elemento de un agregado es tambi´n un iterador para dicho agregado. int n = 0. Dpto.end(). } // 0 1 2 3 4 5 6 7 8 9 typedef std::map<std::string.16. ++i) { // *i = n.begin(). 0 } vi_crit inicio_secuencia_inversa_const = vi. 4 .base().rbegin(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .. inversos std::vector<int> vect_int. i es un const_iterator << " ". const RIT& rit) { it = rit. i es un const_iterator cout << *i << " ".rbegin(). ++i) { // error. i != vi. 2 . 7 . INVERSOS 115 for (vi_cit i = vi.rend(). it != mapa.++it) { std::cout << "Clave: " << it->first << " Valor: " << it->second << std::endl.rbegin(). template <typename IT. vi_crit fin_secuencia_inversa_const = vi. for (vi_crit i // *i = n.rend(). 6 7 8 9 vi_rit rit = . typedef typedef typedef typedef const int MAX = 10. 5 . } // vi = { 9 .rend(). unsigned> MapStrUint.16. for (vi_rit i = vi. vect_int::const_reverse_iterator vi_crit. y puede e ser utilizado como tal el los algoritmos que lo requieran. vect_int::reverse_iterator vi_rit. i != vi. ostream_iterator<int> os(cout). typedef std::insert_iterator<contenedor> iic. // anade elementos en posicion 16. *os = 79. istringstream str_entrada(entrada). bit = std::back_inserter(contenedor). typedef std::front_insert_iterator<contenedor> fiic.116 ´ CAP´ ITULO 16. const string& entrada. ++os. ++is. BIBLIOTECA ESTANDAR DE C++. it_pos). int i1 = *is. copy(input_string_stream_it. inserters “Inserters” producen un iterador que al ser utilizado para asignar objetos. int i2 = *is. aumentando as´ su tama˜o. Ejemplo que lee numeros de un string y los pasa a un vector: #include #include #include #include #include <iostream> <string> <vector> <iterator> <sstream> using namespace std. istream_iterator<int> is(cin). stream iterators ostream_iterator<int> os(cout. } Ejemplo que copia el contenido de un fichero a otro: #include #include #include #include <iostream> <fstream> <algorithm> <iterator> using namespace std. istream_iterator<unsigned> input_string_stream_it(str_entrada). void copiar_fichero(const string& salida. bool& ok) Dpto. e ı n typedef std::back_insert_iterator<contenedor> biic. back_inserter(v)). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . copy(is. "delimitador_de_salida"). void str2vect(const string& entrada.18.clear(). istream_iterator<int> fin_entrada. fin_input_string_stream_it. vector<unsigned>& salida) { salida. STL 16. fin_entrada. back_inserter(salida)). istream_iterator<unsigned> fin_input_string_stream_it. *os = 7. alojan espacio para ´l en el contenedor.17. // anade elementos al final del contenedor fiit = std::front_inserter(contenedor). // anade elementos al inicio del contenedor iit = std::inserter(contenedor. fit_ent. //-----------------------------------struct FileNotFound : public FileIOError { explicit FileNotFound(const char* w) : FileIOError(w) {} explicit FileNotFound(const string& w) : FileIOError(w) {} }.18.16. STREAM ITERATORS { typedef istream_iterator<char> Iterador_Entrada. typedef ostream_iterator<char> Iterador_Salida. Iterador_Entrada it_ent(f_ent). } InputIt entrada(in). y salva dicho contenedor a un fichero: #include #include #include #include #include #include <iostream> <fstream> <string> <vector> <iterator> <algorithm> using namespace std.fail()) { throw FileNotFound(filename). ifstream f_ent(entrada.c_str()).close(). ifstream in(filename. f_sal. Iterador_Salida it_sal(f_sal). InputIt fin_entrada. // no es necesario } f_ent.c_str()). Contenedor& c) throw(FileNotFound. ok = false.c_str()).close(). //-----------------------------------template <typename Contenedor> void cargar(const string& filename. copy(it_ent. struct FileIOError : public std::runtime_error { explicit FileIOError(const char* w) : std::runtime_error(w) {} explicit FileIOError(const string& w) : std::runtime_error(w) {} }. if (in. if (f_ent) { ofstream f_sal(salida. Iterador_Entrada fit_ent.unsetf(ios::skipws). f_sal). Dpto. struct FileFormatError : public FileIOError { explicit FileFormatError(const char* w) : FileIOError(w) {} explicit FileFormatError(const string& w) : FileIOError(w) {} }. if (f_sal) { entrada. FileFormatError) { typedef istream_iterator<typename Contenedor::value_type> InputIt. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . // no es necesario } } 117 Ejemplo que carga el contenido de un fichero a un contenedor. get_area(). ifstream in(filename. } InputIt entrada(in). //c. //c.fail()) { throw FileNotFound(filename). PtrFun ptr_fun. explicit Apply(TipoB& o. if (in.clear().c_str()). void> { typedef void (TipoB::*PtrFun)(const TipoE&). const Procedure1& proc1) throw(FileNotFound. if (!in. InputIt fin_entrada. FileFormatError) { typedef istream_iterator<typename Contenedor::value_type> InputIt.118 ´ CAP´ ITULO 16. template <typename TipoB. pred1(p) {} void operator()(const TipoE& e) const { if (pred1(e)) { (obj. std::for_each(entrada. TipoB& obj. ptr_fun(f). PtrFun ptr_fun. ptr_fun(f) {} void operator()(const TipoE& e) const { (obj. Predicate1 pred1.clear(). not1(pred1)). proc1). std::remove_copy_if(entrada. fin_entrada). PtrFun f) : obj(o). } }. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . STL //c. back_inserter(c)). typename Predicate1> struct ApplyIf : public std::unary_function<TipoE. Contenedor& c. fin_entrada. TipoB& obj. const Predicate1& pred1) throw(FileNotFound. if (!in. bool> { string val. template <typename TipoB. } }. InputIt fin_entrada. void> { typedef void (TipoB::*PtrFun)(const TipoE&). typename TipoE. } InputIt entrada(in). typename TipoE> struct Apply : public std::unary_function<TipoE. if (in.c_str()). typename Predicate1> void cargar(const string& filename.eof()) { throw FileFormatError(filename).assign(entrada. PtrFun f. back_inserter(c). ifstream in(filename. explicit ApplyIf(TipoB& o. explicit AreaEq(const string& a) : val(a) {} bool operator()(const Tipo& v) const { return val == v.eof()) { throw FileFormatError(filename). } } template <typename Contenedor. std::copy(entrada.*ptr_fun)(e). fin_entrada. } } template <typename Procedure1> void aplicar(const string& filename. FileFormatError) { typedef istream_iterator<typename Procedure1::argument_type> InputIt. Dpto. } } %------------------------------------template <typename Tipo> struct AreaEq : public std::unary_function<Tipo. fin_entrada. if (!in.fail()) { throw FileNotFound(filename).eof()) { throw FileFormatError(filename).*ptr_fun)(e). const Predicate1& p) : obj(o). BIBLIOTECA ESTANDAR DE C++. } } //-----------------------------------int main() { vector<int> cnt. const Predicate1& pred1) throw(FileNotFound. typename Predicate1> void salvar(const string& filename. cargar(cnt.c_str()). " "). } } template <typename Tipo> struct MayorQue : public std::unary_function<Tipo.19.begin(). c. } } template <typename Contenedor.fail()) { throw FileNotFound(filename). if (out. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . "salida.+= -= Comparac | | == != | == != | == != | == != < > >= <= ------------+-------+-------+-------+-------+---------------------Dpto. AreaEq<Profesor>(cfg. " ").AreaEq<AsgNAT> >(asignaturas. "entrada. ofstream out(filename. FileFormatError) { typedef ostream_iterator<typename Contenedor::value_type> OutputIt.txt". c. ofstream out(filename. salvar(cnt.txt"). ApplyIf<Asignaturas.19. } OutputIt salida(out. const Contenedor& c) throw(FileNotFound.AsgNAT. if (out. copy(c. aplicar(filename. MayorQue(5)). if (out. profesores. 119 cargar(filename. remove_copy_if(c. salida.+ .end().16.c_str()). if (out.fail()) { throw FileNotFound(filename). Operaciones sobre Iteradores Operaciones sobre Iteradores |Salida |Entrada|Avance |Bidir |Random ------------+-------+-------+-------+-------+---------------------Leer | | =*p | =*p | =*p | =*p Acceso | | -> | -> | -> | -> [] Escribir | *p= | | *p= | *p= | *p= Iteracion | ++ | ++ | ++ | ++ -.fail()) { throw FileFormatError(filename).end().fail()) { throw FileFormatError(filename). not1(pred1)).area)). const Contenedor& c. bool> { Tipo base. FileFormatError) { typedef ostream_iterator<typename Contenedor::value_type> OutputIt.| ++ -.begin(). explicit MayorQue(const Tipo& x) : base(x) {} bool operator()(const Tipo& x) const { return x > base. salida).&Asignaturas::set_sin_prio } 16. OPERACIONES SOBRE ITERADORES } } }. //-----------------------------------template <typename Contenedor> void salvar(const string& filename. } OutputIt salida(out. end(). second_argument_type. li. func2(obj1.begin(). bool > { bool operator() (const Tipo& x) const { return !x. . argumento_fijo_1). } }. Ej: of(obj) se convierte a obj->m1(). class persona_eq : public unary_function< persona . obj2). const Tipo& y) const { return x < y. vi. t2 a2) const {} //base de los objetos unary_function<argument_type. func1(obj). } }. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .end(). o ligando un argumento a un valor fijo. bind2nd(less<int>(). c. objeto_funcion_unario = bind1st(operacion_binaria. obj2). //Objetos funcion => res operator() (t1 a1. } }.nombre. bool cmp2(obj1.begin(). }.it2> p1 = mismatch(vi. result_type> template <typename Tipo> struct logical_not : public unary_function < Tipo . BIBLIOTECA ESTANDAR DE C++. Objetos Funci´n y Predicados o #include <functional> using namespace std.begin(). public: explicit persona_eq(const string& n) : _nm(n) {} bool operator() (const persona& p) const { return _nm == p. lc. 7)). STL 16. // bool less<Tipo>(o1. less<int>()). Adapter: convierte la llamada a una funci´n con un objeto como argumento a una llamada o a un m´todo de dicho objeto. it = find_if(lc. e objeto_funcion_unario = mem_fun(ptr_funcion_miembro_0_arg). bool pred1(obj). Dpto. pair<it1. Creacion de Objetos funcion a partir de existentes Binder: permite que una funcion de 2 argumentos se utilice como una funci´n de 1 argumento. argumento_fijo_2).20. persona_eq("pepe")). bool pred2(obj1. . . objeto_funcion_unario = bind2nd(operacion_binaria.end(). bool > { const string _nm. Tipo .begin().120 ´ CAP´ ITULO 16. template <typename Tipo> struct less : public binary_function < Tipo . proc2(obj1. obj2). bool > { bool operator() (const Tipo& x. o2) void void tipo tipo proc1(obj). obj2). it = find_if(c. struct persona { string nombre. result_type> binary_function<first_argument_type. l. bind2nd(mem_fun1(&Shape::rotate). l.end()) { return NULL. 30)).end().end(). OBJETOS FUNCION Y PREDICADOS objeto_funcion_unario = mem_fun_ref(ptr_funcion_miembro_0_arg). l. not1(bind2nd(ptr_fun(strcmp).end(). Negater: permite expresar la negaci´n de un predicado. o objeto_funcion_unario = not1(predicado_unario). ls. it = find_if(l.begin(). l. } else { Dpto. // elem. "pepe"))). l. * bind2nd(equal_to<string>(). mem_fun_ref(&Shape::draw)). Un adaptador de puntero a funci´n crea un objeto funci´n equivalente a una funci´n. bind2nd(mem_fun1_ref(&Shape::rotate). // l es un contenedor<Shape> elem. // l es un contenedor<Shape*> elem->rotate(30) for_each(l.´ 16. LI p = find_if(ls.end(). not2(less<int>())). // elem.begin(). not1(bind2nd(ptr_fun(strcmp). objeto_funcion_binario = mem_fun1_ref(ptr_funcion_miembro_1_arg). /* * Busca la primera ocurrencia de ’cad’ en lista */ const char* buscar(const List_str& ls.empty() objeto_funcion_binario = mem_fun1(ptr_funcion_miembro_1_arg). 121 // l es un contenedor<Shape*> for_each(l. cad) ). li. // elem->draw() // l es un contenedor<Shape> for_each(l. mem_fun_ref(&string::empty)). 30)). Ejemplo: #include #include #include #include <iostream> <string> <list> <algorithm> using namespace std. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . /* * LI p = find_if(ls. Para o o o utilizar funciones con los “binders” y “adapters”. l.begin().begin().20.end().end(). objeto_funcion_binario = not2(predicado_binario).begin(). not1(bind2nd(ptr_fun(strcmp).end(). const char* cad) { typedef List_str::const_iterator LI.end().rotate(30) for_each(l.begin(). l.begin().begin().begin(). cad)) ). p1 = mismatch(l.end(). l.draw() // l es un contenedor<string> it = find_if(l.begin().begin(). ls. typedef list<const char*> List_str. mem_fun(&Shape::draw)).end(). objeto_funcion_unario = ptr_fun(ptr_funcion_1_arg). "pepe"))). objeto_funcion_binario = ptr_fun(ptr_funcion_2_arg). */ if (p == ls. it = find_if(l. y) less_equal <tipo> (x. y) multiplies <tipo> (x. l. b) logical_not <tipo> (b) Objetos Operaciones Aritm´ticas e plus <tipo> (x. const char* nm = buscar(lista. l.122 return *p. lista.push_back("pepe"). } } Objetos Predicados equal_to <tipo> (x. pred2) // p = mismatch(f. proc1) // aplica proc1 a [f:l) it = find(f. if (nm == NULL) { cout << "No encontrado" << endl. y) logical_and <tipo> (b. b) logical_or <tipo> (b. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . x) // busca x en [f:l) it = find_if(f. u) // busc prim [p:u) en [f:l) it = find_first_of(f. pred1) // b = equal(f. f2. lista. y) not_equal_to <tipo> (x. p. f2. y) modulus <tipo> (x. BIBLIOTECA ESTANDAR DE C++. y) less <tipo> (x. l. l. l. l) // encuentra adyacentes iguales it = adjacent_find(f. y) negate <tipo> (x) 16. y) greater_equal <tipo> (x. } ´ CAP´ ITULO 16.push_back("lola"). Algoritmos #include <algorithm> Operaciones que no modifican la secuencia for_each(f. lista. y) divides <tipo> (x.push_back("maria"). f2) // busca la primera diferencia p = mismatch(f. pred2) // Dpto. f2) // compara 2 secuencias b = equal(f.push_back("juan"). y) greater <tipo> (x. y) minus <tipo> (x. l.21. pred2) // it = adjacent_find(f. l. l. lista. u. x) // cuenta cuantas veces aparece x en [f:l) n = count_if(f. l. l. l. pred1) // busca si pred es true en [f:l) it = find_first_of(f. l. } else { cout << nm << endl. "lola"). pred2) // n = count(f. p. STL } int main() { List_str lista. m. l. d) random_shuffle(f. it = remove_if(f. l. u) // search hacia atras find_end(f. p. l. g) it = remove(f. u) // buscan una subsecuencia en otra search(f. nv) fill(f. l. l. v) generate(f. l) Dpto.erase(p.begin(). c. g) generate_n(f. Lenguajes y Ciencias de la Computaci´n o // ordena [f:l) (O(n*log(n)).end()). func1) // copia [f:l) a d aplicando func1 transform(f. l. v) fill_n(f. O(n*n) peorcaso ) // ordena [f:l) segun cmp2 // ordena [f:l) (O(n*log(n)*log(n))) Universidad de M´laga a . n. c. pred1. g) // baraja aleatoriamente donde aparece d => back_inserter(c) para eliminar en el mismo contenedor: sort(c. Ordenaciones sort(f. nv) // reemplaza v por nv en [f:l) replace_if(f. n. itb) swap_ranges(f. l. l. l) rotate_copy(f. pred2)// 123 Operaciones que modifican la secuencia transform(f. l. pred1) d. p. l. d. l. ALGORITMOS it it it it it it = = = = = = search(f. l. d) copy_backward(f. v. c. l. pred2)// search_n(f. m. d. l. x) // busca la sec "x n veces" en [f:l) search_n(f. x. func2) // copia [f:l) a d aplicando func2 copy(f. l.16. n. d. cmp2) stable_sort(f. d) rotate(f. d) // copia [f:l) a d // copia [f:l) a d (hacia atras) // intercambia los elementos a y b // intercambia los elementos *ita y *itb // swap [f:l) por [d:dd) replace(f. v. l.end()). l) it = unique(f. n. nv) // reemplaza si pred1 por nv en [f:l) replace_copy(f. it p = unique(c. remove_copy(f. l) sort(f. d) reverse(f.end()). c. u. ff. l. l. l) random_shuffle(f. l. u. remove_copy_if(f. pred1. p. l. l. d. p. l.21. l. pred2) // find_end(f. l. v) l.begin(). d) swap(a. pred1) // elimina copias adyacentes de [f:l) // elimina copias adyacentes de [f:l) // copia sin duplicaciones de [f:l) a d // invierte el orden de los elementos // invierte el orden de los elementos // rota [f:l) hasta que m sea el primero it = unique(f. nv) // reemplaza v por nv de [f:l) en d replace_copy_if(f. l) reverse_copy(f. l. d. pred1) unique_copy(f. b) iter_swap(ita. // pone los valores de [f:l) a v // pone n valores a partir de f a v // pone los valores de [f:l) a g() // pone n valores a partir de f a g() v) // elimina elementos de [f:l) iguales a v l. ff. cmp2) max(a. prev_permutation(f. ll. l) // pone el n-esimo elemento en su posicion nth_element(f. l. l. ll) // < lexicographical_compare(f. pred1) // mueve los elementos que satisfacen pred1 stable_partition(f. d) Heap make_heap(f. cmp2) // ordena [f:m) partial_sort_copy(f. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . cmp2) Permutaciones b b b b = = = = next_permutation(f. l . ff. l. l) push_heap(f. l. v. ll. l) sort_heap(f. b) max(a. ll. l) max_element(f. l. ff. d) set_difference(f. next_permutation(f. l. BIBLIOTECA ESTANDAR DE C++. l. v) // primer elemento mayor a v parit = equal_range(f. l. ff. m. l. l . l . l) l. ll. cmp2) // pone el n-esimo elemento en su posicion it = lower_bound(f. cmp2) lexicographical_compare(f. cmp2) l) l. ff. cmp2) min_element(f. prev_permutation(f. l) pop_heap(f. ll. l. cmp2)// merge(f. ff. l) Comparaciones x x x x x x x x b b = = = = = = = = = = min(a. m .l) // mezcla ordenada partition(f. cmp2)// nth_element(f. b) min(a. ll) // partial_sort_copy(f. l. m. STL partial_sort(f. l. b. cmp2) max_element(f. ll) set_union(f. cmp2) 16. l) min_element(f. l) // ordena [f:m) partial_sort(f. ll. l. b. v) // rango de elementos igual a v b = binary_search(f. v) // primer elemento mayor o igual a v it = upper_bound(f. Garant´ (excepciones) de operaciones sobre conteıas nedores | vector | deque | list | map -------------------+-----------------------------------------------------clear() | nothrow nothrow nothrow nothrow | (copy) (copy) Dpto. l. l. n . ll. l. d) set_symmetric_difference(f. ff. ff. v) // busqueda binaria (si esta) b = binary_search(f. pred1) // mueve los elementos que satisfacen pred1 Conjuntos b = includes(f. ff. ff.22. l.124 ´ CAP´ ITULO 16. n . d) set_intersection(f. l. d) // mezcla ordenada inplace_merge(f. l) v = accumulate(f.. d) // [a. vi. etc) no dejen a los elementos del contenedor en un estado inv´lido. se garantiza que no elevar´ excepciones. o tiene ´xito o no tiene efecto. f2_1. basic las invariantes b´sicas de la biblioteca se mantienen y no se producen perdidas de recursos a (como la memoria) strong adem´s de la b´sica. l) v = inner_product(f. d. b-a. ff. a+b.*it2)) . swap. adjacent_difference(f.. f2_2) // v = f2_1(vi..] adjacent_difference(f. F2_2(*it1..23. l. a a a 16.. l. a+b+c..] -> [a.23. v = inner_product(f. ff. l. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . c.16. c-b.] -> [a. . Numericos #include <numeric> v = accumulate(f.. func2) partial_sum(f. l. b. a a o e nothrow adem´s de la b´sica.. NUMERICOS erase() | nothrow nothrow nothrow nothrow | (copy) (copy) 1-element insert() | strong strong strong strong | (copy) (copy) N-element insert() | strong strong strong basic | (copy) (copy) merge() | ---------nothrow ----| (comparison) push_back() | strong strong strong ----| push_front() | ----strong strong ----| pop_back() | nothrow nothrow nothrow ----| pop_front() | ----nothrow nothrow ----| remove() | --------nothrow ----| (comparison) remove_if() | --------nothrow ----| (predicate) reverse() | --------nothrow ----| splice() | --------nothrow ----| swap() | nothrow nothrow nothrow nothrow | (copy-of-comparison) unique() | --------nothrow ----| (comparison) -------------------+------------------------------------------------------ 125 Las siguientes garant´ se ofrecen bajo la condici´n de que las operaciones suministradas por ıas o el usuario (asignaciones. d) // [a. l.. a que no pierdan recursos. func2) // v = f2(vi. vi. F2(*it)) ParaTodo it in [f. . vi) // v = vi + SUM(*it) ParaTodo it in [f. b. . la operaci´n. d. l..] partial_sum(f. l. c. .. vi) // v = vi + SUM(*it1 * *it2) .. y que los destructores no eleven excepciones. l. func2) Dpto. const type_info& typeid(expression) throw(bad_typeid).25.5. // digitos excluyendo signo numeric_limits<char>::is_signed = true. } numeric_limits<float>::quiet_NaN() { return xx. BIBLIOTECA ESTANDAR DE C++. } numeric_limits<float>::infinity() { return xx. 16. } numeric_limits<char>::max() { return 128. L´ ımites #include <limits> numeric_limits<char>::is_specialized = true. numeric_limits<float>::is_integer = false. bool before (const type_info&) const. numeric_limits<float>::has_denorm = denorm_absent. } numeric_limits<float>::is_specialized = true. } numeric_limits<float>::max() { return 3. } numeric_limits<float>::signaling_NaN() { return xx. Dpto. numeric_limits<char>::digits = 7. }. numeric_limits<float>::round_style = round_to_nearest. } // 1+epsilon-1 numeric_limits<float>::round_error() { return 0. // base del exponente numeric_limits<float>::digits = 24. Run Time Type Information (RTTI) #include <typeinfo> class type_info { public: virtual ~type_info().40282347E+38F. // numero de digitos (base10) en mantisa numeric_limits<float>::is_signed = true. numeric_limits<float>::max_exponent10 = +38. numeric_limits<float>::traps = true. numeric_limits<float>::is_iec559 = true. numeric_limits<float>::is_modulo = false. numeric_limits<float>::max_exponent = +128. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . numeric_limits<float>::is_bounded = true. STL 16. const char* name() const. numeric_limits<float>::has_quiet_NaN = true. numeric_limits<float>::min_exponent10 = -37.19209290E-07F. numeric_limits<float>::has_infinity = true. numeric_limits<float>::is_exact = false. } numeric_limits<float>::epsilon() { return 1.24. numeric_limits<char>::min() { return -128. numeric_limits<float>::radix = 2.17549435E-38F. } numeric_limits<float>::denorm_min() { return min(). numeric_limits<float>::tinyness_before = true. bool operator!= (const type_info&) const. numeric_limits<char>::is_integer = true. numeric_limits<float>::has_denorm_loss = false. numeric_limits<float>::min() { return 1. bool operator== (const type_info&) const.126 ´ CAP´ ITULO 16. const type_info& typeid(type_name) throw(). numeric_limits<float>::has_signaling_NaN = true. // numero de digitos (radix) en mantisa numeric_limits<float>::digits10 = 6. } numeric_limits<float>::min_exponent = -125. tales como entornos con excepciones. elimina auto_ptr<> y define en su lugar unique_ptr<> a como mecanismo adecuado para expresar el propietario de un recurso de memoria din´mica. el nuevo est´ndard de C++0x. entonces se puede revocar dicha caracter´ ıstica. la biblioteca est´ndar proporciona a la clase auto_ptr. 17. 127 . N´tese que este mecanismo permite dise˜ar mecanismos robustos de gesti´n o o n o de recursos en situaciones complejas. Sin a a embargo. En a o caso de que haya pasado la zona donde se pueden elevar excepciones.Cap´ ıtulo 17 T´cnicas de programaci´n usuales e o en C++ En este cap´ ıtulo veremos algunas t´cnicas de programaci´n usualmente utilizadas en C++. la zona de memoria apuntada por ella se libera (delete) autom´tia camente.1. de tal forma que la destrucci´n del manager lleva asociado la o liberaci´n del recurso. a El est´ndar de C++98 define el tipo auto_ptr<> para gestionar la memoria din´mica. Adquisici´n de recursos es Inicializaci´n o o (DRAFT) Esta t´cnica consiste en que las adquisici´n de recursos se realiza en la inicializaci´n de un e o o objeto que lo gestiona (manager).1. las zonas de memoria din´mica reservada se deber´n proteger o a a de esta forma para que sean liberadas autom´ticamente en caso de que se eleve una excepci´n. a Esta clase se comporta igual que el tipo puntero (“smart pointer”) pero con la salvedad de que cuando se destruye la variable. De esta forma. 17. Las e o t´cnicas mostradas en este cap´ e ıtulo han sido tomadas de diferentes recursos p´blicos obtenidos de u Internet. salvo que se indique lo contrario mediante el m´todo release. si hay e posibilidad de lanzar una excepci´n. o mediante managers que poseen recursos y permiten la n transferencia de propiedad a otros managers.1. Ejemplo: #include <iostream> #include <memory> using namespace std. class Dato { unsigned val. auto ptr (unique ptr) Para soportar la t´cnica “Adquisici´n de recursos es inicializaci´n” con objeto de implementar e o o clases que se comporten de forma segura ante las excepciones. Nota: auto_ptr no debe ser utilizado dentro de los contenedores est´ndares. Se puede dise˜ar de forma simple. cout << "Valor2: " << (*ptr2).ptr). o #include <iostream> using namespace std. RaiiPtr& operator=(const RaiiPtr& o). } 17.. Dpto. } }. . } catch (.1. RAII simple de memoria din´mica a Un gestor de recursos simple. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . }. public: X(). sin transferencia de propiedad. auto_ptr<Dato> ptr2. TECNICAS DE PROGRAMACION USUALES EN C++ public: ~Dato() throw() { cout << "Destruye dato " << val << endl.release().get() paux. template <typename PtrBase> class RaiiPtr { PtrBase* ptr.2. public: ~RaiiPtr() throw() { try { delete ptr. } X::X() : ptr(0) { auto_ptr<int> paux(new int). X::~X() throw{} { delete ptr.. class Dato { unsigned val.. } }. o. a donde la adquisici´n del recurso de realiza durante la inicializaci´n del objeto. zona posible de excepciones // *paux paux-> paux. } unsigned get() const { return val.) {} } explicit RaiiPtr(PtrBase* p) : ptr(p) {} void swap(RaiiPtr& o) { std::swap(this->ptr. especifico para memoria din´mica.128 ´ ´ CAP´ ITULO 17. } PtrBase* operator->() const throw() { return ptr. ptr2 = ptr1. } PtrBase* get() const throw() { return ptr. } Dato(unsigned v = 0): val(v) { cout << "Construye dato " << val << endl. y su liberaci´n o o o durante la destrucci´n del mismo.get() << endl.. cout << "Valor1: " << ptr1->get() << endl. // utilizacion de paux.reset(p) ptr = paux. } Otro ejemplo de utilizaci´n o #include <memory> class X { int* ptr. int main() { auto_ptr<Dato> ptr1(new Dato(5)). } PtrBase& operator*() const throw() { return *ptr. o. } }. int main() { cout << "----------------" << endl.owner). } void swap(Raii& o) { std::swap(this->owner. RAII simple gen´rico e #include <iostream> using namespace std. } unsigned get() const { return val.get() << endl..get() << endl. template <typename Releaser> class Raii { mutable bool owner. rlsr(o. std::swap(this->rlsr. ptr1. const Releaser& rlsr.ptr). public: ~Raii() throw() { if (owner) { try { rlsr(). int main() { RaiiPtr<Dato> ptr1(new Dato(5)). Raii<PtrReleaser<Dato> > mngr1(ptr1).swap(ptr2). } void operator()() const { delete ptr. cout << "Valor2: " << (*ptr2). o. template <typename PtrBase> class PtrReleaser { const PtrBase* ptr. } Raii& operator=(const Raii& o) { if (this != &o) { Raii(o).1. cout << "Valor1: " << (*ptr1). } }. public: ~PtrReleaser() throw() {} PtrReleaser(const PtrBase* p) : ptr(p) {} void swap(PtrReleaser& o) { std::swap(this->ptr. rlsr(r) {} Raii(const Raii& o): owner(o.. } Dato(unsigned v = 0): val(v) { cout << "Construye dato " << val << endl.1. } return *this. Dato* ptr1 = new Dato(5). } }. } void release() const throw() { owner = false.´ ´ 17. cout << "Valor1: " << ptr1->get() << endl. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .release(). } Dpto.) {} } } explicit Raii(const Releaser& r): owner(true). cout << "Valor2: " << ptr2->get() << endl.3. o. } 129 17. cout << "Valor1: " << ptr1->get() << endl.rlsr). ADQUISICION DE RECURSOS ES INICIALIZACION public: ~Dato() throw() { cout << "Destruye dato " << val << endl.swap(*this). } catch (.owner). RaiiPtr<Dato> ptr2(new Dato(7)).rlsr) { o. _arg(a) {} }.// class SGuard1Arg //--------------------------------------------------------------------Dpto. } public: void release() const throw() { _released = true.) {} }} SGuard2Arg(const Fun& f.) {} }} SGuard1Arg(const Fun& f.cuj. } catch(. const Arg1& a1. const Arg& a) : _fun(f). _arg2(a2) {} }.// class SGuardImplBase //--------------------------------------------------------------------template <typename Fun> class SGuard0Arg : public SGuardImplBase { const Fun& _fun. const Arg1& _arg1... public: ~SGuard2Arg() throw() { if (!_released) { try{ _fun(_arg1. public: ~SGuard0Arg() throw() { if (!_released) { try{ _fun(). } }. } catch(.) {} }} SGuard0Arg(const Fun& f) : _fun(f) {} }. TECNICAS DE PROGRAMACION USUALES EN C++ 17.130 ´ ´ CAP´ ITULO 17. typename Arg> class SGuard1Arg : public SGuardImplBase { const Fun& _fun.// class SGuard1Arg //-------------------------------template <typename Fun. public: ~SGuard1Arg() throw() { if (!_released) { try{ _fun(_arg).4.com/documents/s=8000/cujcexp1812alexandr/ */ namespace raii { //--------------------------------------------------------------------class SGuardImplBase { SGuardImplBase& operator=(const SGuardImplBase& o). RAII gen´rico e //------------------------------------------------------------------------#ifndef _guard_hpp_ #define _guard_hpp_ /* * Generic<Programming>: * Change the Way You Write Exception-Safe Code ? Forever * Andrei Alexandrescu and Petru Marginean * C/C++ User Journal * http://www.. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . const Arg2& _arg2.._arg2). } catch(. const Arg2& a2) : _fun(f).release().. const Arg& _arg. _arg1(a1). typename Arg2> class SGuard2Arg : public SGuardImplBase { const Fun& _fun. ~SGuardImplBase() throw() {} // nonvirtual SGuardImplBase() throw() : _released(false) {} SGuardImplBase(const SGuardImplBase& o) throw() : _released(o. typename Arg1.//prohibida protected: mutable bool _released.// class SGuard1Arg //-------------------------------template <typename Fun..1._released) { o. aunque hay otras menores que no comentaremos: Puntero a la implementaci´n. guarda_rec_1. dicha caracter´ ıstica se puede simular muy fac´ ılmente con las herramientas que C++ ofrece.Arg> mk_guard(const Fun& f. Hay dos corrientes principales a la hora de solucionar el problema. } //-------------------------------template <typename Fun.2. } //-------------------------------template <typename Fun.. public: Dpto.hpp ------------------------------------------------------------#ifndef _elem_hpp_ #define _elem_hpp_ namespace elem { class Elem { class ElemImpl.release(). int main() { // adquisicion de recurso Recurso rec_1 = acquire_resource(). typename Arg2> inline SGuard2Arg<Fun. // Anulacion de liberacion automatica del recurso } //------------------------------------------------------------------------- 131 17. const Arg1& a1. typename Arg1.Arg2> mk_guard(const Fun& f. // . a)..Arg>(f. // liberacion automatica de recurso si surge una excepcion SGuard guarda_rec_1 = mk_guard(funcion. Ocultar la implementaci´n o Aunque C++ no soporta directamente tipos opacos.Arg2>(f. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . arg). const Arg2& a2) { return SGuard2Arg<Fun. // Acciones que pueden elevar una excepcion // . //--------------------------------------------------------------------}// namespace raii #endif //------------------------------------------------------------------------// _EJEMPLO_DE_USO_ //-----------------------------------using namespace raii. ElemImpl* pimpl. const Arg& a) { return SGuard1Arg<Fun.Arg1. OCULTAR LA IMPLEMENTACION template <typename Fun> inline SGuard0Arg<Fun> mk_guard(const Fun& f) { return SGuard0Arg<Fun>(f).. o //-.Arg1.elem. a2)..´ 17. a1. } //--------------------------------------------------------------------typedef const SGuardImplBase& SGuard.2. typename Arg> inline SGuard1Arg<Fun. void swap(Elem& o).cpp ------------------------------------------------------------#include "elem.set_val(7). public: ~ElemImpl() throw() { cout << "destruccion de: " << val << endl.val) {} //ElemImpl& operator=(const ElemImpl& o) { val = o.set_val(e2. Elem& operator=(const Elem& o). void set_val(int).main.// class ElemImpl Elem::~Elem() throw() { delete pimpl. } Elem::Elem() : pimpl(new ElemImpl) {} Elem::Elem(const Elem& o) : pimpl(new ElemImpl(*o.hpp" using namespace std. Elem(const Elem& o). } }.hpp" #include <iostream> using namespace std. cout << e.val.get_val() << endl. e.swap(*this). Elem e2(e). using namespace elem. Elem().get_val() << endl. cout << e2. } int get_val() const { return val.// class Elem } //namespace elem #endif //-. namespace elem { class Elem::ElemImpl { int val. } ElemImpl() : val(0) {} //ElemImpl(const Elem& o) : val(o. int get_val() const. Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . TECNICAS DE PROGRAMACION USUALES EN C++ ~Elem() throw(). cout << e2. return *this.get_val()+2).elem. e2.132 ´ ´ CAP´ ITULO 17.cpp ------------------------------------------------------------#include <iostream> #include "elem. int main() { Elem e. } void set_val(int v) { val = v. return *this. e2 = e. } int Elem::get_val() const { return pimpl->get_val(). } //-.get_val() << endl.pimpl)) {} Elem& Elem::operator=(const Elem& o) { Elem(o). }. cout << e2->get_val() << endl.elem. int val.´ 17. pimpl = aux. //-.cpp ------------------------------------------------------------#include <iostream> #include <memory> #include "elem.hpp" #include <iostream> using namespace std. val(0) {} Dpto.cpp ------------------------------------------------------------//#include "elem. e->set_val(7). }. public: virtual ElemImpl* clone() const { return new ElemImpl(*this). virtual Elem* clone() const = 0. cout << e->get_val() << endl. namespace { class ElemImpl : public elem::Elem { typedef elem::Elem _ClaseBase. } //-. virtual int get_val() const = 0.main.pimpl = pimpl. cout << e2->get_val() << endl. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . virtual ~Elem() throw().hpp ------------------------------------------------------------#ifndef _elem_hpp_ #define _elem_hpp_ namespace elem { class Elem { public: static Elem* create(). using namespace elem. e2 = auto_ptr<Elem>(e->clone()). int main() { auto_ptr<Elem> e(Elem::create()).// class Elem } //namespace elem #endif //-. auto_ptr<Elem> e2(e->clone()). } ElemImpl() : _ClaseBase(). } void Elem::swap(Elem& o) { ElemImpl* aux = o. OCULTAR LA IMPLEMENTACION } void Elem::set_val(int v) { pimpl->set_val(v). } }// namespace elem //-.pimpl.hpp" using namespace std. e2->set_val(e2->get_val()+2). o. virtual void set_val(int) = 0.2.elem.fin ------------------------------------------------------------------ 133 Base abstracta. } virtual ~ElemImpl() throw() { cout << "destruccion de: " << val << endl. matriz.fin ------------------------------------------------------------------ 17.hpp ----------------------------------------------------------#ifndef _matriz_hpp_ #define _matriz_hpp_ /* * Matriz Dispersa * * Definicion de tipos * * typedef Matriz<int> Mat_Int. 3U). NCOL).134 ´ ´ CAP´ ITULO 17.// class ElemImpl } namespace elem { Elem* Elem::create() { return new ElemImpl(). } virtual int get_val() const { return val. } }. * * Definicion de Constantes * * const Mat_Int aux2(mat). * * Definicion de Variables * * Mat_Int mat(NFIL. TECNICAS DE PROGRAMACION USUALES EN C++ //ElemImpl(const Elem& o) : _ClaseBase(o). template <typename Tipo> class Ref_Elm.3. * * Operaciones * * aux1 = mat. // asignacion a elemento * x = mat(1U. pero o manteniendo el control sobre las operaciones que se realizan sobre el mismo: //-.val. 3U) = 4. // numero de elementos almacenados * mat(1U. // numero de filas * unsigned ncol = mat. } virtual void set_val(int v) { val = v. // paso de parametros * unsigned nfil = mat.getnelm(). // valor de elemento * * Excepciones * * OutOfRange */ #include <map> #include <iterator> namespace matriz { class OutOfRange {}. return *this.val) {} //ElemImpl& operator=(const ElemImpl& o) { val = o. // asignacion * print(mat). } Elem::~Elem() throw() {} }// namespace elem //-. Dpto. Control de elementos de un contenedor En esta secci´n veremos como acceder a elementos de un contenedor definido por nosotros.getncol(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . val(o. // numero de columnas * unsigned nelm = mat.getnfil(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . typedef typename Lista_Fila::const_iterator ItCFil. //-. Lista_Fila elm. unsigned nc) : nfil(nf). typedef typename Lista_Fila::iterator ItFil. } unsigned getncol() const { return ncol. // const Matriz_Elm* mat.3. friend class RefC_Elm<Tipo>. Lista_Fila.Matriz ------------------------------------template <typename Tipo> class Matriz { friend class Ref_Elm<Tipo>. // typedef Tipo Tipo_Elm. ncol(nc) {} unsigned getnfil() const { return nfil. typedef Matriz<Tipo_Elm> Matriz_Elm. fil(f). unsigned f.RefC_Elm ----------------------------------template <typename Tipo> class RefC_Elm { friend class Matriz<Tipo>. // atributos unsigned nfil.Tipo_Elm> typedef std::map<unsigned. 135 typedef typename Lista_Elm::iterator ItElm. unsigned fil. }. } unsigned size() const. Dpto. unsigned c) : mat(m). unsigned getnfilalm() const { return elm.17. // typedef Tipo Tipo_Elm. }//DEBUG const Tipo_RefC_Elm operator() (unsigned f. unsigned c) const throw(OutOfRange). unsigned col. public: Matriz(unsigned nf. }. typedef typename Lista_Elm::const_iterator ItCElm. unsigned ncol. typedef RefC_Elm<Tipo_Elm> Tipo_RefC_Elm. // RefC_Elm(const Matriz_Elm* m. col(c) {} public: operator Tipo_Elm () const. unsigned c) throw(OutOfRange).// class Matriz //-. CONTROL DE ELEMENTOS DE UN CONTENEDOR template <typename Tipo> class RefC_Elm.size().Lista_Elm> Lista_Elm. Tipo_Ref_Elm operator() (unsigned f. // typedef Tipo Tipo_Elm.Ref_Elm -----------------------------------template <typename Tipo> class Ref_Elm { friend class Matriz<Tipo>. typedef Matriz<Tipo_Elm> Matriz_Elm. typedef Ref_Elm<Tipo_Elm> Tipo_Ref_Elm.// class RefC_Elm //-. typedef std::map<unsigned. unsigned c) throw(OutOfRange) { if ((f >= nfil)||(c >= ncol)) { throw OutOfRange(). if (itfil == mat->elm. unsigned c) : mat(m).find(fil). if (itelm == itfil->second. typedef typename Matriz_Elm::ItCFil ItCFil. } return Tipo_RefC_Elm(this.end()) { return Tipo_Elm(). fil(f).// class Ref_Elm //-.Matriz ------------------------------------template <typename Tipo> const typename Matriz<Tipo>::Tipo_RefC_Elm Matriz<Tipo>::operator() (unsigned f. } template <typename Tipo> unsigned Matriz<Tipo>::size() const { unsigned nelm = 0. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . operator RefC_Elm<Tipo> () const. } //-. } else { return itelm->second. c).size(). ItCFil itfil = mat->elm. TECNICAS DE PROGRAMACION USUALES EN C++ // Matriz_Elm* mat. // Ref_Elm(Matriz_Elm* m. col(c) {} void eliminar_elemento_si_existe(). unsigned f. unsigned c) const throw(OutOfRange) { if ((f >= nfil)||(c >= ncol)) { throw OutOfRange(). i != elm. unsigned fil. } } Dpto. c). } return nelm. f. f. }.end()) { return Tipo_Elm(). for (ItCFil i = elm.RefC_Elm ----------------------------------template <typename Tipo> RefC_Elm<Tipo>::operator typename RefC_Elm<Tipo>::Tipo_Elm () const { typedef typename Matriz_Elm::ItCElm ItCElm.find(col). ++i) { nelm += i->second.136 ´ ´ CAP´ ITULO 17. public: Ref_Elm& operator=(const Tipo_Elm& e). } template <typename Tipo> typename Matriz<Tipo>::Tipo_Ref_Elm Matriz<Tipo>::operator() (unsigned f. unsigned col.begin(). } else { ItCElm itelm = itfil->second. } return Tipo_Ref_Elm(this.end(). find(fil).getncol(). const unsigned NCOL = 6U.erase(itelm).end()) { itfil->second. const unsigned NFIL = 5U. } return *this.main. if (itelm != itfil->second. if (itfil != mat->elm.getnfilalm() << endl. typedef Matriz<int> Mat_Int.end()) { ItElm itelm = itfil->second.empty()) { mat->elm. } else { typename Matriz_Elm::Lista_Elm& fila = mat->elm[fil].find(col). } template <typename Tipo> Ref_Elm<Tipo>& Ref_Elm<Tipo>::operator=(const Tipo_Elm& e) { if (e == Tipo_Elm()) { eliminar_elemento_si_existe(). for (unsigned f = 0. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .erase(itfil). col). void print(const Mat_Int& mat) { cout << "Numero de filas reales: " << mat. fil. if (itfil->second. typedef typename Matriz_Elm::ItFil ItFil.getnfil(). ++f) { for (unsigned c = 0. c < mat. CONTROL DE ELEMENTOS DE UN CONTENEDOR } //-. f < mat.cpp ------------------------------------------------------------#include <iostream> #include <string> #include "matriz. } template <typename Tipo> void Ref_Elm<Tipo>::eliminar_elemento_si_existe() { typedef typename Matriz_Elm::ItElm ItElm. } } } } //----------------------------------------------} //namespace matriz #endif //-.size() << endl. ItFil itfil = mat->elm.17.3.hpp" using namespace std. cout << "Numero de elementos almacenados: " << mat.Ref_Elm -----------------------------------template <typename Tipo> Ref_Elm<Tipo>::operator RefC_Elm<Tipo> () const { return RefC_Elm<Tipo>(mat. using namespace matriz. fila[col] = e. ++c) { 137 Dpto. //aux2(1U. } cout << endl.// elimina un elemento y una fila print(aux1). TECNICAS DE PROGRAMACION USUALES EN C++ cout << mat(f. mat(1U.138 ´ ´ CAP´ ITULO 17. 1U) = 3.. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .// Error de compilacion // Fuera de Rango mat(NFIL. } catch ( . } int main() { try { Mat_Int mat(NFIL.NCOL). ) { cerr << "excepcion inesperada" << endl.ostrcap. 2U) = 0. print(mat).fin ------------------------------------------------------------------ 17. Mat_Int aux1(NFIL.c) << " ". Dpto.NCOL). print(aux2). mat(2U.4. Redirecci´n transparente de la salida est´ndar a un o a string Para que de forma transparente la informaci´n que se env´ a la salida est´ndar se capture en o ıa a un string: //-. NCOL) = 5. mat(1U. 3U) = 4. 2U) = 5. 1U) = 3. } } //-. aux1 = mat.. } cout << endl. const Mat_Int aux2(mat). } catch ( OutOfRange ) { cerr << "excepcion fuera de rango" << endl.hpp -----------------------------------------------------#ifndef _ostrcap_hpp_ #define _ostrcap_hpp_ #include <iostream> #include <string> #include <sstream> #include <stdexcept> namespace ostrcap { class Capture_Error : public std::runtime_error { public: Capture_Error() : std::runtime_error ("Capture_Error") {} Capture_Error(const std::string& arg) : std::runtime_error (arg) {} }. aux1(2U. REDIRECCION TRANSPARENTE DE LA SALIDA ESTANDAR A UN STRING class Release_Error : public std::runtime_error { public: Release_Error() : std::runtime_error ("Release_Error") {} Release_Error(const std::string& arg) : std::runtime_error (arg) {} }. std::streambuf* output_streambuf_ptr. output_stream = &os. } output_stream->rdbuf(output_streambuf_ptr). } std::string release() { if (output_streambuf_ptr == NULL) { throw Release_Error().capture(cout).str("").hpp" using namespace std.´ ´ 17.4. output_streambuf_ptr = NULL. cout << "La salida es: " << ostrcap. output_stream(). salida(34). } str_salida. std::ostream* output_stream.release().main.str(). class OStreamCapture { std::ostringstream str_salida.rdbuf()). salida(36).// class OStreamCapture } //namespace ostrcap #endif //-.release(). using namespace ostrcap. void salida(int x) { cout << "Informacion " << x << endl. } //-. cout << "La salida es: " << ostrcap.capture(cout). public: OStreamCapture() : str_salida(). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .cpp ---------------------------------------------------------#include <iostream> #include <string> #include "ostrcap. ostrcap. output_streambuf_ptr = output_stream->rdbuf(str_salida. return str_salida.fin ------------------------------------------------------------------ 139 Dpto. output_streambuf_ptr() {} void capture(std::ostream& os) { if (output_streambuf_ptr != NULL) { throw Capture_Error(). ostrcap. } int main() { OStreamCapture ostrcap. } }. 5. } Is_Vector() { void(*p)(T1) _UNUSED_ = constraints. Restricciones en programaci´n gen´rica o e En programaci´n gen´rica puede ser conveniente especificar un conjunto de restricciones sobre o e los tipos gen´ricos que pueden ser intanciados en diferentes clases o funciones: e //-.T2.~constraint.T2) _UNUSED_ = constraints. a<b.6. a!=b. } }.T3) _UNUSED_ = constraints. TECNICAS DE PROGRAMACION USUALES EN C++ 17. typename T2. template<typename T1. T3 c) { c = a*b. DD : D { }. a[0]. typename T3 = T1> struct Can_Multiply { static void constraints(T1 a. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . } }. } Can_Copy() { void(*p)(T1. typename T2> struct Can_Copy { static void constraints(T1 a.T2) _UNUSED_ = constraints. } }. template<typename T1. typename T2 = T1> struct Can_Compare { static void constraints(T1 a.140 ´ ´ CAP´ ITULO 17. T2 b) { T2 c = a. } }. template<typename T1. b = a. } Can_Multiply() { void(*p)(T1.constraint. X { }.size(). // Los elementos deben ser derivados de ’ClaseBase’ template<typename T> Dpto. D : B { }. } Derived_From() { void(*p)(T*) _UNUSED_ = constraints. struct struct struct struct B { }. } }. T2 b) { a==b. T2 b. typename B> struct Derived_From { static void constraints(T* p) { B* pb = p.hpp ------------------------------------------------------ Un ejemplo de su utilizacion: #include <iostream> using namespace std.hpp ------------------------------------------------------// Tomado de: B. Stroustrup Technical FAQ #ifndef _constraint_hpp_ #define _constraint_hpp_ #ifndef _UNUSED_ #ifdef __GNUC__ #define _UNUSED_ __attribute__((unused)) #else #define _UNUSED_ #endif #endif namespace constraint { template<typename T. } //namespace constraint #ifdef _UNUSED_ #undef _UNUSED_ #endif //-. } Can_Compare() { void(*p)(T1. template<typename T1> struct Is_Vector { static void constraints(T1 a) { a. Eventos registrando listener que heredan de una base abstracta listener 17. int main() { Derived_from<D.float>().float>().X>(). Can_compare<X.double>(). Derived_from<int. } 141 Dpto.. Can_copy<int. }.B>(). Can_copy<D*. Can_multiply<int.int>().6. Can_compare<int. Derived_from<X. Can_copy<D.float.B>(). Can_multiply<B. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .. Derived_from<X.´ ´ 17.B*>().B>().B*>().ClaseBase> { // .B>(). template<typename T> class Nuevo : Is_Vector<T> { // ... Derived_from<DD. Can_multiply<int. }.B*>(). RESTRICCIONES EN PROGRAMACION GENERICA class Container : Derived_from<T.B>(). TECNICAS DE PROGRAMACION USUALES EN C++ Dpto.142 ´ ´ CAP´ ITULO 17. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . o y en caso de agotamiento de memoria devolver´n 0. Tambi´n existe la posibilidad de crear un objeto llamando a otro contructor: new Tipo(args). const std::nothrow_t&) throw(). e El operador delete ptr se encarga de destruir el objeto apuntado (llamando al destructor) y de liberar la memoria ocupada llamando a void operator delete(void *) throw(). Tipo* ptr = new (nothrow) Tipo[nelms]. Los operadores anteriores elevan la excepci´n std::bad_alloc en caso de agotamiento de la o memoria.1. Si queremos que no se lance dicha excepci´n se pueden utilizar la siguiente modalidad. Devuelve un puntero al primer objeto especificado. Se implementan en base a los siguientes operadores: void void void void *operator new(std::size_t. Tipo* ptr = new (nothrow) Tipo(args). const std::nothrow_t&) throw().Cap´ ıtulo 18 Gesti´n Din´mica de Memoria o a 18. Gesti´n de Memoria Din´mica o a Los operadores new y delete en sus diferentes modalidades solicitan y liberan memoria din´mia ca. operator delete[](void *. y crea un objeto (constructor por defecto) de dicho tipo. El operador new Tipo[nelms] reserva espacio en memoria para contener nelms elementos del tipo especificado llamando a void *operator new[](std::size_t) throw (std::bad_alloc). Devuelve un puntero al objeto creado. *operator new[](std::size_t. const std::nothrow_t&) throw(). y crea dichos elementos llamando al constructor por defecto. operator delete(void *. ı El operador new Tipo se encarga de reservar memoria del tama˜o necesario para contener un n elemento del tipo especificado llamando a void *operator new(std::size_t) throw (std::bad_alloc). as´ como crean y destruyen objetos alojados en ella. 143 . const std::nothrow_t&) throw(). El operador delete [] ptr se encarga de destruir los objetos apuntados (llamando al destructor) en el orden inverso en el que fueron creados y de liberar la memoria ocupada por ellos llamando a void operator delete[](void *) throw(). a Tipo* ptr = new (nothrow) Tipo. Dpto. inline void *operator new(std::size_t. void *place) throw() { return place. // alojar mem * try { * new (ptr) Tipo(lista_val). const std::nothrow_t&) throw(). } y los comportamientos por defecto podr´ ser los siguientes para los operadores new y delete: ıan Los operadores new y delete encargados de alojar y desalojar zonas de memoria pueden ser redefinidos por el programador. const std::nothrow_t&) throw(). operator delete(void *. *operator new[](std::size_t) throw (std::bad_alloc). * ******************************** * * ptr = static_cast<Tipo*>(::operator new(sizeof(Tipo))).com/c++-faq-lite/) #include <new> extern "C" void *malloc(std::size_t). C++ FAQ-Lite. void *place) throw() { return place. extern "C" void free(void *).) { * ::operator delete(ptr). Lenguajes y Ciencias de la Computaci´n o */ Universidad de M´laga a . operator delete(void *) throw(). /* malloc(0) es impredecible. void *place) throw() { return place.. operator delete[](void *) throw(). } Los operadores encargados de reservar y liberar memoria din´mica y pueden redefinirse para a las clases definidas por el usuario [tambien pueden redefinirse en el ´mbito global. * throw.. /* * ******************************** * Tipo* ptr = new Tipo(lista_val). Cline. simplemente crea el objeto del tipo especificado (utilizando el constructor por defecto u otra clase de constructor con la sintaxis new (ptr) Tipo(args) en la zona de memoria especificada por la llamada con argumento ptr a inline void *operator new(std::size_t.144 ´ ´ CAP´ ITULO 18. extern std::new_handler __new_handler. tanto en el ´mbito global como para clases espec´ a ıficas. lo evitamos. const std::nothrow_t&) throw(). // llamada al constructor * } catch (. operator delete[](void *. *operator new[](std::size_t. * } */ void* operator new (std::size_t sz) throw(std::bad_alloc) { void* p. *operator new(std::size_t.parashift. o o http://www. aunque esto a ultimo no es aconsejable] ´ #include <new> void void void void void void void void *operator new(std::size_t) throw (std::bad_alloc). Una definici´n estandar puede ser como se indica a continuaci´n: (fuente: M. } inline void *operator new[](std::size_t. const std::nothrow_t&) throw(). if (sz == 0) { sz = 1. GESTION DINAMICA DE MEMORIA El operador new (ptr) Tipo (new con emplazamiento) no reserva memoria. * size_t i.!= 0) { * (p+i)->~Tipo(). #else std::abort(). if (handler == 0) { #ifdef __EXCEPTIONS throw std::bad_alloc(). // liberar zona de memoria * } * * ******************************** */ void operator delete (void* ptr) throw() { if (ptr) { free(ptr). while (p == 0) { std::new_handler handler = __new_handler.´ ´ 18. // llamada al destructor * ::operator delete(ptr). ++i) { * new (ptr+i) Tipo(). p = static_cast<void*>(malloc(sz)).. * ptr = (Tipo*)(tmp+WORDSIZE). i < NELMS. #endif } handler().1. * } * ::operator delete((char*)ptr . * ******************************** * * if (ptr != 0) { * ptr->~Tipo(). GESTION DE MEMORIA DINAMICA } p = static_cast<void*>(malloc(sz)). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .. // llamada al constructor * } * } catch (. } /* * ******************************** * delete ptr. * try { * for (i = 0. * } * * ******************************** */ 145 Dpto. * *(size_t*)tmp = NELMS.WORDSIZE). * ***************************** * * // alojar zona de memoria * char* tmp = (char*)::operator new[](WORDSIZE+NELMS*sizeof(Tipo)).) { * while (i-. * throw. } return p. } } /* * ***************************** * Tipo* ptr = new Tipo [NELMS]. const Tipo& val). las zonas de memoria din´mica reservada se deber´n proteger o a a de esta forma para que sean liberadas autom´ticamente en caso de que se eleve una excepci´n.146 ´ ´ CAP´ ITULO 18. uninitialized_fill(For_It begin. la biblioteca est´ndar proporciona a la clase auto_ptr. salvo que se indique lo contrario mediante el m´todo release. uninitialized_fill_n(For_It begin.!= 0) { * (ptr+n)->~Tipo(). etc. In_It end_org. entonces se puede revocar dicha caracter´ ıstica. } /* * ************** * delete [] ptr. } La biblioteca est´ndar tambi´n proporciona una clase para poder trabajar con zonas de memoria a e sin inicializar. de forma que sea util para la creaci´n de clases contenedoras. De esta forma. Esta clase se comporta igual que el tipo puntero (“smart pointer”) pero con la salvedad de que cuando se destruye la variable. void construct(Tipo* ptr. const Tipo& val). const Tipo& val). Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . std::size_t nelms) throw(). std::size_t nelms. construir objetos en ella. // llamada al destructor * } * ::operator delete[]((char*)ptr .WORDSIZE). For_It end. void destroy(Tipo* ptr). destruir objetos e de ella y liberar dicha zona: #include <memory> template <typename Tipo> class allocator { public: Tipo* allocate(std::size_t nelms) throw(std::bad_alloc). * while (n-. * } * * ********** */ void operator delete[] (void* ptr) throw() { ::operator delete (ptr). }. la zona de memoria apuntada por ella se libera (delete) autom´tia camente. As´ proporciona ´ o ı.WORDSIZE). For_It begin_dest). GESTION DINAMICA DE MEMORIA void* operator new[] (std::size_t sz) throw(std::bad_alloc) { return ::operator new(sz). void deallocate(Tipo* ptr. uninitialized_copy(In_It begin_org. En a o caso de que haya pasado la zona donde se pueden elevar excepciones. m´todos para reservar zonas de memoria sin inicializar. Ejemplo: #include <memory> Dpto. si hay e posibilidad de lanzar una excepci´n. Para soportar la t´cnica “Adquisici´n de recursos es inicializaci´n” con objeto de implementar e o o clases que se comporten de forma segura ante las excepciones. * ************** * * if (ptr != 0) { * size_t n = *(size_t*)((char*)ptr . X::~X() throw{} { delete ptr. } X::X() : ptr(0) { auto_ptr<int> paux(new int). } 147 Dpto. public: X().get() paux. GESTION DE MEMORIA DINAMICA class X { int* ptr. }.release(). . zona posible de excepciones // *paux paux-> paux..1. // utilizacion de paux.. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .reset(p) ptr = paux.´ ´ 18. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . GESTION DINAMICA DE MEMORIA Dpto.148 ´ ´ CAP´ ITULO 18. | +-----------------------------------------------------------------------+ +-----------------------------------------------------------------------+ | Constantes Caracter: | | [\n=NL] [\t=TAB] [\v=VTAB] [\b=BS] [\r=RC] [\f=FF] [\a=BEL] | +-----------------------------------------------------------------------+ 149 . a izq. a izq. a dcha. | | << >> | izq. C no especifica el orden en el cual | | Los operandos de un operador seran evaluados (excepciones | | son && || ?: .Ap´ndice A e Precedencia de Operadores en C +-----------------------------------------------------------------------+ | Precedencia de Operadores y Asociatividad | +-----------------------------------------------+-----------------------+ | Operador | Asociatividad | +-----------------------------------------------+-----------------------+ | () [] -> . a dcha. a dcha. | | ! ~ ++ -. ]]] | | .. | | || | izq. | izq. | | && | izq. | izq. a dcha. ]]] | | * / % | izq. a dcha. | +-----------------------------------------------+-----------------------+ +-----------------------------------------------------------------------+ | Orden de Evaluacion | +-----------------------------------------------------------------------+ | Pag. La coma se evalua de izda a dcha y el valor | | que toma es el de la derecha. ]]] | | = += -= *= /= %= &= ^= |= <<= >>= | [[[ dcha. 58-59 K&R 2 Ed. a dcha.(tipo) * & sizeof | [[[ dcha. | | Como muchos lenguajes. | | ^ | izq. | | + | izq. a izq. a dcha. el orden en que se evaluan los argumentos de una | | funcion no esta especificado. a dcha. | | ?: | [[[ dcha. a dcha. | | Asi mismo. | | & | izq. a dcha.). | | == != | izq. a dcha. | | | | izq. a dcha. | | < <= > >= | izq. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . PRECEDENCIA DE OPERADORES EN C Dpto.150 ´ APENDICE A. Ap´ndice B e Precedencia de Operadores en C++ =============================================================================== nombre_clase::miembro Resolucion de ambito nombre_esp_nombres::miembro Resolucion de ambito ::nombre Ambito global ::nombre_calificado Ambito global ----------------------------------------------------------------------------objeto.*puntero_a_miembro Seleccion de miembro 151 .miembro Seleccion de miembro puntero->miembro Seleccion de miembro puntero[expr] Indexacion expr(list_expr) Llamada a funcion tipo(list_expr) Construccion de valor valor_i++ Post-incremento valor_i-Post-decremento typeid(tipo) Identificacion de tipo typeid(expr) Identificacion de tipo en tiempo de ejecucion dynamic_cast<tipo>(expr) Conversion en TEjecucion con verificacion static_cast<tipo>(expr) Conversion en TCompilacion con verificacion reinterpret_cast<tipo>(expr) Conversion sin verificacion const_cast<tipo>(expr) Conversion const ----------------------------------------------------------------------------sizeof expr Tama~no del objeto sizeof(tipo) Tama~no del tipo ++valor_i Pre-incremento --valor_i Pre-decremento ~expr Complemento !expr Negacion logica -expr Menos unario +expr Mas unario &valor_i Direccion de *expr Desreferencia new tipo Creacion (asignacion de memoria) new tipo(list_expr) Creacion (asignacion de memoria e iniciacion) new tipo [expr] Creacion de array (asignacion de memoria) new (list_expr) tipo Creacion (emplazamiento) new (list_expr) tipo(list_expr) Creacion (emplazamiento e inciacion) delete puntero Destruccion (liberacion de memoria) delete [] puntero Destruccion de un array (tipo) expr Conversion de tipo (obsoleto) ----------------------------------------------------------------------------objeto. expr Resta ----------------------------------------------------------------------------expr << expr Desplazamiento a izquierda expr >> expr Desplazamiento a derecha ----------------------------------------------------------------------------expr < expr Menor que expr <= expr Menor o igual que expr > expr Mayor que expr >= expr Mayor o igual que ----------------------------------------------------------------------------expr == expr Igual expr != expr No igual ----------------------------------------------------------------------------expr & expr AND de bits ----------------------------------------------------------------------------expr ^ expr XOR de bits ----------------------------------------------------------------------------expr | expr OR de bits ----------------------------------------------------------------------------expr && expr AND logico ----------------------------------------------------------------------------expr || expr OR logico ----------------------------------------------------------------------------expr ? expr : expr Expresion condicional ----------------------------------------------------------------------------valor_i = expr Asignacion simple valor_i *= expr Multiplicacion y asignacion valor_i /= expr Division y asignacion valor_i %= expr Modulo y asignacion valor_i += expr Suma y asignacion valor_i -= expr Resta y asignacion valor_i <<= expr Despl izq y asignacion valor_i >>= expr Despl dch y asignacion valor_i &= expr AND bits y asignacion valor_i ^= expr XOR bits y asignacion valor_i |= expr OR bits y asignacion ----------------------------------------------------------------------------throw expr Lanzar una excepcion ----------------------------------------------------------------------------expr . ----------------------------------------------------------------------------Los operadores de casillas mas altas tienen mayor precedencia que los operadores de casillas mas bajas. los operadores de asignacion y el operador condicional son asociativos por la derecha. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . PRECEDENCIA DE OPERADORES EN C++ puntero->*puntero_a_miembro Seleccion de miembro ----------------------------------------------------------------------------expr * expr Multiplicacion expr / expr Division expr % expr Modulo ----------------------------------------------------------------------------expr + expr Suma expr . ----------------------------------------------------------------------------Los operadores unitarios. Dpto. expr Secuencia =============================================================================== =============================================================================== Notas ----------------------------------------------------------------------------Cada casilla contine operadores con la misma precedencia.152 ´ APENDICE B. 124 =============================================================================== Dpto. ----------------------------------------------------------------------------Sacado de "El Lenguaje de Programacion C++" de B. Stroustrup.153 Todos los demas son asociativos por la izquierda. pg. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .154 ´ APENDICE B. PRECEDENCIA DE OPERADORES EN C++ Dpto. // // // // // // // // // // // (isalpha(ch) || isdigit(ch)) (isupper(ch) || islower(ch)) caracteres de control digito decimal caracteres imprimibles excepto espacio letra minuscula caracteres imprimibles incluyendo espacio carac. ispunct(char ch).2. bool bool bool bool bool bool bool bool bool bool bool cctype isalnum(char ch). char* strncat(char dest[]. isalpha(char ch). const char orig[]. const char orig[]). // Concatena la cadena orig a la cadena dest. \n. hasta como maximo ’n’ caracteres int strcmp(const char s1[]. iscntrl(char ch). // Si aparece ’n’. C. 155 . unsigned n). const char s2[]. unsigned n). const char s2[]). int strncmp(const char s1[]. isgraph(char ch). islower(char ch). isprint(char ch). // convierte ch a minuscula // convierte ch a mayuscula C. hasta como maximo ’n’ caracteres char* strcat(char dest[]. \v.Ap´ndice C e Biblioteca b´sica ANSI-C (+ a conio) En este ap´ndice veremos superficialmente algunas de las funciones m´s importantes de la e a biblioteca estandar de ANSI-C y C++. // Si aparece ’n’. \f letra mayuscula digito hexadecimal #include <cctype> char tolower(char ch). isspace(char ch). cstring #include <cstring> char* strcpy(char dest[]. isdigit(char ch). const char orig[]. const char orig[]). // Copia la cadena orig a dest (incluyendo el terminador ’\0’). impr. char toupper(char ch). isupper(char ch). unsigned n). \r. excepto espacio. \t. letra o digito esp. isxdigit(char ch).1. char* strncpy(char dest[]. // devuelve la longitud del prefijo de s1 de caracteres // que NO se encuentran en s2 char* strpbrk(const char s1[]. const void* origen. // Si aparece ’n’. // copia n caracteres de origen a destino. // coloca el caracter ch en los primeros n caracteres de m1 C. // devuelve un apuntador a la primera ocurrencia en s1 // de la cadena s2. char ch. const void* m2. // devuelve la longitud de la cadena s1 void* memcpy(void* dest. // devuelve la longitud del prefijo de s1 de caracteres // que se encuentran en s2 unsigned strcspn(const char s1[]. // Compara lexicograficamente ’n’ caracteres de m1 y m2 // devuelve <0 si m1<m2. 0 si s1==s2. char ch).156 ´ ´ APENDICE C. // cadena a double Dpto. const char s2[]). NO Valido si se solapan void* memmove(void* dest. >0 si s1>s2 char* strchr(const char s1[]. Valido si se solapan int memcmp(const void* m1. const char s2[]). 0 si m1==m2. unsigned n). hasta como maximo ’n’ caracteres // devuelve <0 si s1<s2. char ch). char ch. unsigned n). Si fallo -> != 0 int rename(const char oldname[].3. unsigned n). unsigned n). // devuelve un apuntador a la primera ocurrencia de ch // en los primeros n caracteres de m1. // devuelve un apuntador a la primera ocurrencia en s1 // de cualquier caracter de s2. unsigned n).4. NULL si no se encuentra void* memset(void* m1. // copia n caracteres de origen a destino. cstdio #include <cstdio> int remove(const char filename[]). // devuelve un apuntador a la ultima ocurrencia de ch en s1 // NULL si no se encuentra unsigned strspn(const char s1[]. NULL si no se encuentra unsigned strlen(const char s1[]). const char newname[]). const char s2[]). const char s2[]). BIBLIOTECA BASICA ANSI-C (+ CONIO) // Compara lexicograficamente las cadenas s1 y s2. cstdlib #include <cstdlib> double atof(const char orig[]). >0 si m1>m2 void* memchr(const void* m1. const void* origen. C. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . NULL si no se encuentra char* strstr(const char s1[]. // devuelve un apuntador a la primera ocurrencia de ch en s1 // NULL si no se encuentra char* strrchr(const char s1[]. // elimina filename. sinh(double rad). unsigned long strtoul(const char orig[]. int base). asin(double x). CASSERT int atoi(const char orig[]). tan(double rad). // // // // // // // // // // // // // // seno de rad (en radianes) coseno de rad (en radianes) tangente de rad (en radianes) arco seno de x. Aborta y mensaje si expresion es falsa // si NDEBUG esta definido. // cadena a int // cadena a long 157 double strtod(const char orig[]. long strtol(const char orig[]. // orden a ejecutar por el sistema operativo char* getenv(const char nombre[]). // valor absoluto // valor absoluto C. double x). atan2(double y. x en [-1. int rand(). x en [-1.0)). // devuelve el valor de la variable de entorno ’nombre’ int abs(int n). x > 0 logaritmo decimal log10(x).5. acos(double x). double y).C.1] arco tangente de x arco tangente de y/x seno hiperbolico de rad coseno hiperbolico de rad tangente hiperbolica de rad e elevado a x logaritmo neperiano ln(x). tanh(double rad). cosh(double rad). se ignora la macro C. // terminacion normal del programa int atexit(void (*fcn)(void)). atan(double x). void srand(unsigned semilla). char** endp).// devuelve un aleatorio entre 0 y RAND_MAX (ambos inclusive) /* Devuelve un numero aleatorio entre 0 y max (exclusive) */ unsigned aleatorio(int max) { return unsigned(max*double(rand())/(RAND_MAX+1. x > 0 x elevado a y Universidad de M´laga a #include <cmath> double double double double double double double double double double double double double double Dpto. char** endp. long atol(const char orig[]). cmath sin(double rad). char** endp. cos(double rad). exp(double x).6. cassert #include <cassert> void assert(bool expresion). // aborta el programa como error void exit(int estado).1] arco coseno de x. int base). long labs(long n). // funcion a ejecutar cuando el programa termina normalmente int system(const char orden[]). // srand(time(0)). } void abort(). pow(double x. // macro de depuracion.5. log(double x). log10(double x). Lenguajes y Ciencias de la Computaci´n o . 158 double double double double double double double double ´ ´ APENDICE C. BIBLIOTECA BASICA ANSI-C (+ CONIO) sqrt(double x); ceil(double x); floor(double x); fabs(double x); ldexp(double x, int n); frexp(double x, int* exp); modf(double x, double* ip); fmod(double x, double y); // // // // // // // // raiz cuadrada de x, x >= 0 menor entero >= x mayor entero <= x valor absoluto de x x * 2 elevado a n inversa de ldexp parte entera y fraccionaria resto de x / y C.7. ctime #include <ctime> clock_t clock(); // devuelve el tiempo de procesador empleado por el programa // para pasar a segundos: double(clock())/CLOCKS_PER_SEC // en un sistema de 32 bits donde CLOCKS_PER_SEC = 1000000 // tiene un rango de 72 minutos aproximadamente. (c2-c1) time_t time(time_t* tp); // devuelve la fecha y hora actual del calendario double difftime(time_t t2, time_t t1); // devuelve t2 - t1 en segundos time_t mktime(struct tm* tp); struct tm* gmtime(const time_t* tp); C.8. climits #include <climits> CHAR_BIT = 8 CHAR_MAX CHAR_MIN UCHAR_MAX SCHAR_MAX SCHAR_MIN | SHRT_MAX | SHRT_MIN | USHRT_MAX | | | INT_MAX | INT_MIN | UINT_MAX | LONG_MAX | LONG_LONG_MAX | LONG_MIN | LONG_LONG_MIN | ULONG_MAX | ULONG_LONG_MAX C.9. cfloat // menor numero float X tal que 1.0+X != 1.0 // maximo numero de punto flotante // minimo numero normalizado de punto flotante // menor numero double X tal que 1.0+X != 1.0 // maximo numero double de punto flotante // minimo numero double normalizado de punto flotante // menor numero long double X tal que 1.0+X != 1.0 // maximo numero long double de punto flotante // minimo numero long double normalizado de punto flotante #include <cfloat> FLT_EPSILON FLT_MAX FLT_MIN DBL_EPSILON DBL_MAX DBL_MIN LDBL_EPSILON LDBL_MAX LDBL_MIN C.10. conio.h (no es estandar ANSI) Universidad de M´laga a #include <conio.h> Dpto. Lenguajes y Ciencias de la Computaci´n o C.10. CONIO.H 159 - Salida y entrada de texto int cprintf(const char *fmt, ...); // envia texto formateado a la pantalla int cputs(const char *_str); // envia una cadena de caracteres a pantalla int putch(int _c); // envia un caracter simple a pantalla int cscanf(const char *fmt, ...); // entrada formateada de datos de consola char *cgets(char *_str); // entrada de una cadena de caracteres de consola int getche(void); // lee un caracter (con eco) int getch(void); // lee un caracter (sin eco) int kbhit(void); // comprueba si hay pulsaciones de teclado int ungetch(int); // devuelve el caracter al buffer de teclado - Manipulacion de texto (y cursor) en pantalla void clrscr(void); // borra e inicializa la pantalla void clreol(void); // borra la linea desde el cursor al final void delline(void); // elimina la linea donde se encuentra el cursor void gotoxy(int x, int y); // posiciona el cursor void insline(void); // inserta una linea en blanco int movetext(int _left, int _top, int _right, int _bottom, int _destleft, int _desttop); // copia texto de una zona de pantalla a otra - Movimientos de bloques int gettext(int _left, int _top, int _right, int _bottom, void*_destin); // copia texto de pantalla a memoria int puttext(int _left, int _top, int _right, int _bottom, void*_source); // copia texto de memoria a pantalla - Control de ventanas void textmode(int _mode); // pone el modo texto void window(int _left, int _top, int _right, int _bottom); // define una ventana de texto void _set_screen_lines(int nlines); void _setcursortype(int _type); // _NOCURSOR, _SOLIDCURSOR, _NORMALCURSOR - Ajuste de color del texto y del fondo void textcolor(int _color); // actualiza el color de texto void textbackground(int _color); // actualiza el color de fondo void textattr(int _attr); // actualiza el color de texto y el de fondo al mismo tiempo - Control de intensidad Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a 160 ´ ´ APENDICE C. BIBLIOTECA BASICA ANSI-C (+ CONIO) void intensevideo(void); void highvideo(void); // alta intensidad void lowvideo(void); // baja intensidad void normvideo(void); // intensidad normal void blinkvideo(void); // parpadeo - Informacion void gettextinfo(struct text_info *_r); // informacion sobre la ventana actual int wherex(void); // valor de la coordenada x del cursor int wherey(void); // valor de la coordenada y del cursor struct text_info { unsigned char winleft; unsigned char wintop; unsigned char winright; unsigned char winbottom; unsigned char attribute; unsigned char normattr; unsigned char currmode; unsigned char screenheight; unsigned char screenwidth; unsigned char curx; unsigned char cury; }; // // // // Numero de lineas de la pantalla Numero de columnas de la pantalla Columna donde se encuentra el cursor Fila donde se encuentra el cursor La esquina superior izquierda se corresponde con las coordenadas [1,1]. Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a Simbolos predefinidos estandares ------------------------------------NDEBUG __LINE__ __FILE__ __DATE__ __TIME__ __STDC__ __STDC_VERSION__ __func__ __cplusplus //-.b) #define concatenar(a.b) //-.b) #undef xxx #xxx mkstr_2(xxx) a##b concat(a.Ap´ndice D e El preprocesador Directivas de preprocesamiento: #include <system_header> #include "user_header" #line xxx #error mensaje #pragma ident #define mkstr_2(xxx) #define mkstr(xxx) #define concat(a.Simbolos predefinidos en GCC ----------------------------------------__GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ __GNUG__ __STRICT_ANSI__ __BASE_FILE__ __INCLUDE_LEVEL__ __VERSION__ __OPTIMIZE__ [-O -O1 -O2 -O3 -Os] __OPTIMIZE_SIZE__ [-Os] __NO_INLINE__ __FUNCTION__ __PRETTY_FUNCTION__ //-------------------------------------------------------------------__linux__ __unix__ __MINGW32__ __WIN32__ 161 . 162 ´ APENDICE D. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .2 o superior sobre GNU/Linux o MinGW/Windows " #error "para usar tipos_control" #elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #else #endif Dpto. EL PREPROCESADOR //-------------------------------------------------------------------#ifndef __STDC__ #ifdef __cplusplus #ifndef NDEBUG #if ! ( defined(__GNUC__) \ && ( (__GNUC__ >= 4) || ((__GNUC__ == 3)&&(__GNUC_MINOR__ >= 2))) \ && ( defined __linux__ || defined __MINGW32__ )) #error "Debe ser GCC version 3. . o if (0 <= x <= 99) { . case 2: cout << "Caso segundo" << endl... } debe ser: switch (x) { case 0: case 1: cout << "Caso primero" << endl. tras las acciones de un case en un switch. break. if (x = y) { . break.. switch (x) { case 0: case 1: cout << "Caso primero" << endl. default: 163 .. } // error: asignacion en vez de comparacion Utilizaci´n de operadores relacionales.. } Olvidar poner la sentencia break. break. } // error: debe ser: if ((0 <= x) && (x <= 99)) { . case 2: cout << "Caso segundo" << endl. break.Ap´ndice E e Errores m´s comunes a utilizar = (asignacion) en vez de == (igualdad) en comparaciones. // error: no hemos puesto el break default: cout << "Caso por defecto" << endl. cadena). en vez de con delete [] p. espacio para ’\0’ strcpy(ptr. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . } Al alojar agregados din´micos para contener cadenas de caracteres. // OK. // error. cadena). ERRORES MAS COMUNES cout << "Caso por defecto" << endl. char* ptr = new char[strlen(cadena)]. // error. Al alojar con tipo* p = new tipo[30]. break. no solicitar espacio para a contener el terminador ’\0’ char cadena[] = "Hola Pepe".164 ´ ´ APENDICE E. copia sin espacio debe ser: char* ptr = new char[strlen(cadena)+1]. Overflow en Arrays y en Cadenas de Caracteres (al estilo C) Dpto. sin espacio para ’\0’ strcpy(ptr. desalojar con delete p. Ap´ndice F e Caracter´ ısticas no contempladas Paso de par´metros variable a 165 . Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a . CARACTER´ ISTICAS NO CONTEMPLADAS Dpto.166 ´ APENDICE F. Ed. Cline http://www.Kernighan. Stroustrup Addison Wesley 2000 C++ FAQ-Lite M. Ritchie Prentice Hall 1991 The C++ Programming Language. 2.Ap´ndice G e Bibliograf´ ıa El Lenguaje de Programacion C. Special Edition B.parashift. D. B.com/c++-faq-lite/ 167 . 13 simb´licas. 15 e conversiones de tipo autom´ticas. 158 cmath. 100 string.´ Indice alfab´tico e ::. 155 ctime. 37 acceso. 69 catch. declaraci´n. 10 Control de flujos. 10 entrada. 35. 156 cstring. 100 operaciones sobre iteradores. 100 operaciones. 53 cadenas de caracteres. 102 resumen. 102 tipos. 66 o using. 16 conversiones enteras. 35. 60 168 . 99 ficheros. 19 buffer. 39 terminador. 11 o definici´n o vs. 158 conio. 11 o delete. 157 cstdio. 36. 31 comentarios. 101 operaciones de lista. 10 constantes literales. 101 operaciones de pila y cola. 35 excepciones. 10 estructura. 49 delimitadores. 37 acceso. 14 o constantes literales. 53. 68 espacios en blanco. 69 throw. definici´n. 20 agregado. 61 entrada. 37 size. 31 declaraci´n o global. 13 o declaraci´n. 60 ejemplo. 66 ::. 69 ficheros. 99 garant´ 124 ıas. 156 cstdlib. 101 o constructores. 68 using namespace. 36. 158 climits. 68 a ´mbito de visibilidad. 69 cin. 37 size. 155 cfloat. 58 de entrada. 101 operaciones asociativas. 19 local.h. 37 n biblioteca ansic cassert. 68 an´nimos. 15 cout. 15 a expl´ ıcitas. 39 campos de bits. 42 catch. 53 de salida. 158 stl acceso. 37 tama˜o. 69 try. 144 delete []. 37 n array. 37 tama˜o. 19 a ´mbito de visibilidad. 157 cctype. 20 vs. 20 a ´mbito de visibilidad. 54 conversiones aritm´ticas. 31 espacios de nombre. 43 bloque. iteradores. 48. 100 asignaci´n. 101 contenedores. 48 a agregados. 65 o implementaci´n. 20 iteraci´n. 144 new T[]. 12 float. 37 size. 14 palabras reservadas. 21 switch. 12 puntero. 39 throw. 25 declaraci´n. 48 registro. 26 salida. 23 for. 27 paso por valor. 31 secuencia de sentencias. 28 Dpto. 35 array. 26 procedimientos. 36. 22 o do while. 58 o formato. 39 terminador. 49 autoreferencia. 11. 41 tipos simples. 15 condicional.´ ´ INDICE ALFABETICO entrada/salida. 19 sentencia asignaci´n. 48 delete. 39 struct. 65 o new. 10. 42 inicializaci´n. 35 uniones. 14 aritm´ticos. 21 o if. 55 jerarqu´ de clases. 13 predefinidos. 50 acceso. 62 salida. 10 inline. 61 flujos entrada. 48 new T[]. 39 a string. 39 campos de bits. 11 tipos cuadro resumen. 56 cadena. 28 return. 62 estado. 56 salida. 26 a paso por referencia. 41 par´metros. 48 m´dulo o definici´n. 47 a subprogramas. 11 bool. 47 e operaciones. 41 o operaciones. 20 o incremento/decremento. 27 paso por referencia constante. 27 a par´metros de salida. 21 string. 26 o inline. 28 o definici´n. 50 par´metros. 49 a tipos compuestos. 49 new. 11 double. 28 o definici´n. 69 tipo. 12 Universidad de M´laga a . 35. 54 excepci´n. 25 declaraci´n. 63 funciones. 11 char. 22 while. 15 puntero nulo. 15 o relacionales. 49 operadores. 48. 22 selecci´n. Lenguajes y Ciencias de la Computaci´n o 169 programa C++. 26 identificadores. 26 a par´metros de entrada/salida. 37 cadenas. 14 e bits. 12 long. 13 ordinales. 57 cadena. 35 return. 15 l´gicos. 11 enumerado. 47 gen´rico. 49 puntero nulo. 26 o inline. 9 promociones. 12 escalares. 12 int. 37 acceso. 28 main. 10 par´metros de entrada. 48 delete []. 9 memoria din´mica. 63 ıa manipuladores. 68 using namespace. 68 variables declaraci´n. 41 using. 69 union. 12 unsigned. 14 o ´ ´ INDICE ALFABETICO Dpto. 12 try.170 short. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a .
Copyright © 2024 DOKUMEN.SITE Inc.