Вы находитесь на странице: 1из 212

Tutorial de programacion, tentativament llamado:

El lenguaje de programacion C++


por Rogelio Cesar Rodriguez Cervantes
(c) copyright 2008-2012, por Rogelio Cesar Rodriguez Cervantes Esta version es una edicion temprana aun en desarrollo, para cualquier comentario y/o sugerencia este es mi email: cesarrdz@gmail.com

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

CONTENIDO
Prefacio Captulo 1 Fundamentos del lenguaje. 1.1 Introduccin al lenguaje y a su entorno de desarrollo... 1.2 Comentarios..... 1.3 Variables y constantes... 1.4 Objetos que permiten E/S por consola.... 1.5 Operadores...... 1.6 Tipos de datos..... 1.6.1 Fundamentales. 1.6.2 Definidos por el usuario..... 1.7 Palabras reservadas... 1.8 Expresiones.. 1.9 Estructuras de control..... 1.9.1 Asignacin. 1.9.2 Seleccin....... 1.9.3 Iteracin. Captulo 2 Subprogramas... 2.1 Definicin de un subprograma.. 2.1.1 Estructura de un subprograma.. 2.1.2 Valor de retorno... 2.2 Declaracin de un subprograma... 2.3 Bibliotecas o librera de subprogramas... 2.4 Primer acercamiento a clases y objetos 2.5 mbito y tiempo de vida de variables.. 2.6 Argumentos y paso de parmetros.. 2.7 Sobrecarga de subprogramas.. 2.8 Recursividad....... Captulo 3 Punteros, referencias y arreglos.. 3.1 Creacin.... 3.2 Operaciones con punteros..... 3.3 Referencias.. 3.4 Arreglos unidimensionales, bidimensionales y multidimensionales.. 3.5 Cadenas de caracteres...... 3.6 Asignacin dinmica de memoria. 3.7 Uso de clases predefinidas para arreglos... Captulo 4 Clases y Objetos.. 4.1 Definicin de una clase.. 4.2 Declaracin de clases.... 4.3 Miembros de una clase.. 4.4 mbito referente a una clase. 4.5 Especificadores de acceso.... 4.6 Creacin de objetos.... 4.7 Puntero this...... 4.8 Constructores y destructores........ iv 1 1 5 8 15 17 21 21 27 33 35 35 36 36 51 58 58 59 60 62 63 67 69 73 77 78 82 82 85 91 94 106 116 129 132 132 132 133 133 134 135 138 142

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

Captulo 5 Herencia.. 5.1 Importancia de la herencia en la POO. 5.2 Jerarqua de herencia.... 5.2.1 Conceptos de herencia simple y mltiple 5.2.2 Principios generales de diseo de jerarquas. 5.2.3 Especificadores de acceso a jerarqua de clases... 5.3 Definicin de una clase base. 5.4 Definicin de una clase derivada.. 5.4.1 Constructores y destructores de clases derivadas. 5.4.2 Conversin implcita de objetos de clase derivada a objeto de clase base.... 5.5 Herencia mltiple..... Captulo 6 Polimorfismo..... 6.1 Concepto de polimorfismo. 6.2 Clase base abstracta..... 6.3 Subprogramas virtuales. 6.4 Destructores virtuales.... Captulo 7 Archivos.. 7.1 Clases de E/S Clase base abstracta.... 7.2 Realizar entrada y salida de texto. 7.3 Leer y escribir archivos... 7.4 Realizar entrada y salida binaria... Bibliografa.

156 156 156 157 158 159 160 165 166 166 173 179 179 182 186 190 193 193 194 194 203 209

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

Prefacio

Se intenta que cada programa de ejemplo sea una aplicacin completa y prctica en la medida que el conocimiento adquirido hasta ese punto lo permita, sin que llegue a ser compleja. Tambin se ha tratado de evitar en todo lo posible el tipo de escritura compacta tradicional de los programas en C/C++ para lograr mayor claridad en los ejemplos. Cuando la presentacin de los programas de ejemplo lo permite (no interfiere con la explicacin) siguen una notacin de anteponer la(s) primera(s) letras de los tipos de datos usados, basada un poco en la notacin hngara. Versin de C++ El material presentado aqu, sigue el estndar de programacin de C++ ISO/IEC 98-14882, por lo tanto los ejemplos podrn ser compilados con cualquier compilador que sigua el estndar ISO Internacional as como el ANSI de Estados Unidos. Los programas de ejemplo fueron compilados con Visual C++ 2008 Express Edition en el sistema operativo Windows XP y con el compilador GNU de C/C+ + en el sistema operativo Linux. Que sea sencillo: lo mas sencillo posible, pero no mas- Albert Einstein

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

Capitulo 1
Fundamentos del lenguaje

1.1 Introduccin al lenguaje y a su entorno de desarrollo.


El lenguaje de programacin C++ fue desarrollado por Bjarne Stroustrup en los laboratorios BELL en 1983, originalmente Stroustup lo llamo C con clases al ser C++ un sper conjunto del lenguaje C; C++ trata de seguir la eficiencia, la rapidez de ejecucin y la libertad de programacin de C con la inclusin de las tcnicas de programacin del modelo orientado a objetos; pero a diferencia de otros lenguaje orientados a objetos, C++ sigue el espritu original del lenguaje C, donde el uso de esas tcnicas depende del programador, as que al igual que en C; en C++ el programador tiene la ltima palabra. Lo mejor de C++ es que permite muchas formas de codificar programas, los paradigmas de programacin ms comunes y que el C++ soporta fcilmente son (Stroustrup 1997): 1. Programacin estructurada 2. Programacin modular 3. Abstraccin de datos 4. Programacin orientada a objetos 5. Programacin genrica

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

El lenguaje C es parte del lenguaje C++, la mayora de las instrucciones de C funcionan en C++, y existen muchas instrucciones equivalentes, en estos casos se ha utilizado las instrucciones de C++ y dejado afuera las de C. Esto no quiere decir que las del Lenguaje C no sean tiles, la capacidad de discernir cuales utilizar en cada caso se obtendr conforme se domine el lenguaje. Los programas de ejemplo siguen la notacin de anteponer la(s) primera(s) letras de los tipos de datos usados, basada un poco en la notacin hngara. Para evitar complejidad innecesaria algunos programas de ejemplo no siguen tal notacin. En C++ el entorno de desarrollo no esta ligado a un solo programa hecho por una sola compaa como en el caso del lenguaje de programacin Visual Basic de Microsoft. Siendo C++ un lenguaje estndar, el entorno de desarrollo depende de la seleccin de entre una variedad de ofertas, as como del sistema operativo que se este utilizando. Independientemente del entorno de desarrollo utilizado, la creacin de programas usando el lenguaje C++ sigue un proceso como se muestra en la figura de la siguiente pagina.

fig1. Diagrama del proceso de creacin de un programa ejecutable usando el lenguaje C++

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

Editor Un programa usado para escribir el texto del lenguaje, este texto es sin formato. Compilador Programa que checa que el lenguaje sea usado correctamente y lo traduce a un lenguaje objeto cercano a lenguaje mquina. Encadenador Programa que toma programas compilados separadamente y los une en un lenguaje de maquina, los deja listo para ejecutarse. Lenguaje Maquina Instrucciones que la computadora entiende directamente. El proceso llamado preprocesador, compilador y el de encadenador se realizan generalmente invocando un solo programa, por ejemplo en una terminal de Linux usando: g++ programa.cpp g++ realiza los tres procesos y deja un programa ejecutable, llamado por omisin "a.out". En el caso de Windows, en la ventana de comandos utilizando borland C++ por ejemplo es como sigue: bcc programa.cpp Dando como salida el programa ejecutable llamado por omisin igual que el de entrada pero con la extensin exe, en este caso "programa.exe". A estos programas g++ y bcc se les llama por el termino general de "compilador" aunque realicen mas cosas que la compilacin (generalmente estos programas mandan llamar otros programas que realizan cada uno un proceso mostrado en la figura de arriba), adems estos compiladores cuentan con opciones para que solo se ejecute uno de los procesos arriba mencionados porque en ocasiones es til hacerlo de esa manera.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

La seleccin de un entorno de desarrollo para C++ depende en gran parte de las necesidades particulares de cada programador, la plataforma de desarrollo y/o la imposicin de este por parte de un empleador, por ejemplo. El entorno de desarrollo puede ser tan escueto como utilizar un editor de texto y un compilador o tan basto como el uso de un entrono de desarrollo integrado, por ejemplo Microsoft Visual C++ en el caso de Windows y Eclipse con el plugin CDT en Windows/Linux.

fig2. Entorno integrado de desarrollo de Microsoft Visual C++ Express Edition

fig3. Entorno integrado de desarrollo de Eclipse con el plugin CDT

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

1.2 Comentarios
Dos diagonales seguidas indican el inicio de un comentario; las diagonales deben estar pegadas sin espacios intermedio. // Primer.cpp // Escribe un mensaje en pantalla Todo lo que esta despus de estos caracteres hasta el fin de la lnea es ignorado por el compilador, se utilizan para poner notas para el programador. Tambin se pueden utilizar los caracteres /* */ para poner comentarios, estos son los usados por el lenguaje C, la ventaja de estos es que pueden ser utilizados para crear bloques de varias lneas, por ejemplo los comentarios anteriores pueden ser lnea por lnea: /* Primer.cpp */ /* Escribe un mensaje en pantalla */ O pueden enmarcar varias lneas: /* Primer.cpp Escribe un mensaje en pantalla */ Los caracteres, diagonal y asterisco deben de ir pegados. El primer programa en C++, el siguiente ejemplo muestra un pequeo programa, que despliega un mensaje en la pantalla, utilizando el objeto cout para realizar salida a la consola. Listado
// Primer.cpp // Escribe un mensaje en pantalla #include <iostream> using namespace std; int main()

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

{ cout << "Este es mi primer programa en C++"; return 0; }

Salida
Este es mi primer programa en C++

Nota: El C++ hace distincin entre minsculas y maysculas, por ejemplo: La palabra Main, es diferente de mAin, o main que es la que reconoce C++.

Aunque el programa de ejemplo anterior es bastante pequeo, este incluye elementos clave que conforman la mayora de los programas en C++. // Primer.cpp // Escribe un mensaje en pantalla Es recomendado incluir como comentarios al inicio de cada programa fuente el nombre del programa as como una breve descripcin de lo que hace. #include <iostream> #include se utiliza para especificar la inclusin de un archivo de texto, el nombre del archivo se pone entre los smbolos menor que y mayor que. En este caso el nombre del archivo de texto es iostream el cual contiene definiciones para realizar entrada y salida de datos por ejemplo leer del teclado y desplegar en pantalla- entre otras cosas. using namespace std; Se asocia, el namespace std para todo el programa e indica que el programa va a utilizar el conjunto de variables globales definidos en el espacio de nombres estndar.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

10

Los espacios entre las palabras se utilizan para separar las instrucciones, las lneas en blanco son ignoradas por el compilador y se utilizan para darle legibilidad al cdigo. int main() main indica donde empieza la ejecucin del programa, int es un tipo de datos (esto se discute mas adelante) e indica el tipo de valor que el programa va a regresar al proceso que lo ejecute. { La llave que abre indica que inicia la ejecucin de un bloque de cdigo } La llave que cierra termina el bloque y ambas { y } enmarcan el cdigo que integra la funcin. cout << "Este es mi primer programa en C++"; Imprime en la consola lo que esta entre comillas "Este es mi primer programa en C++". return 0; return regresa el valor indicado al proceso que lo mando llamar, en este caso un cero y probablemente al Sistema Operativo. Nota: Si esta usando el Sistema Operativo Windows y un IDE (Integrated Development Environment/Entorno de Desarrollo Integrado) como por ejemplo Visual C++ o Dev-C++, puede detener la ejecucin del programa para evitar que se cierre la ventana de comandos (msdos), utilizando:
system("PAUSE > NUL");

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

11

De lo contrario al terminar la ejecucin regrese al IDE como si no hubiera realizado nada el programa. Nota (continua de la pgina anterior):
#include <iostream> using namespace std; int main() { cout << "Este es mi primer programa en C++"; //para pasusa si se ejecuta en un IDE como dev-c++ o vc++ por ej. system("PAUSE > NUL"); return 0; }

system() Es una funcin que permite ejecutar comandos externos. PAUSE es un comando batch del msdos- para detener la ejecucin de un script, la sentencia: PAUSE > NUL redireccina la salida del comando PAUSE a nulo, -la salida de este comando es un mensaje. Los programas de ejemplo no incluyen tal sentencia porque un Entorno de Desarrollo Integrado solo se utiliza cuando se esta desarrollando el programa, cuando el programa (o programas segn sea el caso) esta terminado, este se ejecuta fuera del Entorno de Desarrollo Integrado, por lo tanto tal sentencia dejara de ser til o peor, entorpecera la funcin del programa terminado.

1.3 Variables y constantes


Las variables son lugares de almacenamiento al cual se le asigna un nombre para poder accesar y manipular lo que se guarda en ese lugar. Declaracin de variables

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

12

Una declaracin especifica un tipo y le sigue una lista de una o ms variables de ese tipo. Todas las variables deben de ser declaradas antes de utilizarlas. Ejemplo: int a, b; char c; Al declarar una variable tambin se le pude asignar un valor. Ejemplo: int i = 0; float x = 3.4; Listado
// variables.cpp // Declaracion de variables #include <iostream> using namespace std; int main() { int n, c; c = 2; n = c * c; cout << "El cuadrado de 2 es " << n; return 0; }

Salida
El cuadrado de 2 es 4

Nota:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

13

Un programa es perfectamente legal para el compilador si se escribe en una sola lnea, por Ejemplo: int main() { cout << "Hola"; return 0; } Nota (continua de la pgina anterior): Escribir los programas en varias lneas y con la sangra adecuada mejora la legibilidad de los mismos, algo trivial en programas pequeos pero de de suma importancia en programas reales donde el numero de lneas suman docenas si no es que cientos (Miles en ocasiones). Los programas de ejemplo de aqu en adelante llevan la llave que abre { en la misma lnea del main() principalmente para ahorrar una lnea de espacio y mostrar mas lneas de cdigo en una pantalla de edicin, sin sacrificar legibilidad ya que el int main() indica claramente el inicio del programa (y el nombre de la funcin, estructura, etc., en los ejemplos posteriores).

Ejercicios Declare una variable para cada inciso que pueda ser usada para almacenar el valor mencionado a) 3.1416 b) -554 c) 30000 d) Resultado de 10 * 3 e) Resultado de 10/3 f) 'a' g) "a" h) "HOLA" i) Resultado de 'a' + 'b' j) Resultado de "a" + "b"

Constantes

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

14

Son los valores fijos que el programa no puede alterar, en C++ las constantes tienen un tipo de dato (ver tipos de datos mas adelante) por ejemplo las constantes de carcter, las cuales se encierran entre apstrofes.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

15

Ejemplo: 'a', '%' Distngase que son diferentes: 'a' y "a" 'a' es una constante de carcter compuesta por la letra a y "a" es una cadena de caracteres compuesta por la letra a y el carcter nulo y esta formada de dos elementos. "" es una cadena nula con un elemento (\0). Ejemplo: 123L constante long 123.3 constante float Un cero que encabeza un nmero significa octal Ejemplo: 011 9 en decimal Un cero y una equis antes significa hexadecimal. Ejemplo: 0xFF 255 en hexadecimal. Constantes de carcter no imprimibles Cdigo \b \f \n \r \t \ \ \0 \\ \v \a Significado Retroceso Alimentacin de hoja Nueva lnea Retorno de carro Tabulador horizontal Doble comilla Comilla simple Nulo Barra invertida Tabulador vertical Alerta
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 16

\o \x

Constante octal Constante hexadecimal

Una constante de carcter no imprimible no tiene una representacin grfica solo realiza una accin. Ejemplo: cout << \n; No imprime nada, solo brinca de lnea, es como si presionramos la tecla ENTER/RETORNO. Los dos caracteres \n son interpretados como un solo carcter. Ejemplo: Para desplegar un mensaje con una parte entre comillas por ejemplo: Referencia: C++ Simplificado-pagina 123, se necesita utilizar el carcter no imprimible \ cout << Referencia: \C++ Simplificado\-pagina 123; Si no se antepone la diagonal invertida a las comillas el string termina en las segundas comillas y las terceras comillas produciran un error. Listado
// caracter.cpp // Formato de texto en la salida estndar // utilizando las constantes de carcter no imprimibles #include <iostream> using namespace std; int main(){ cout << "CARACTERES\t\t"; cout << "NO IMPRIMIBLES"; cout << endl << "Esta linea esta en otro renglon"; cout << "\n\n\n\n\nEsta despues de cuatro renglones";

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

17

return 0; }

Salida
CARACTERES NO IMPRIMIBLES Esta linea esta en otro rengln

Esta despues de cuatro renglones

cout << "CARACTERES\t\t"; La secuencia de caracteres \t, indica imprimir un TAB, es como si se presionara la tecla TAB. cout << endl << "Esta linea esta en otro renglon"; La palabra endl despus de los caracteres << indica un salto de lnea antes de imprimir el mensaje. cout << "\n\n\n\n\nEsta despues de cuatro renglones"; El endl se utiliza para cambiar al siguiente rengln, pero en ocasiones es mas practico usar el carcter no imprimible \n. Ejercicio Escriba un programa que imprima sus datos personales centrados lo ms posible en pantalla, utilizando las constantes de carcter no imprimibles.

Constantes simblicas #define

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

18

Mediante esta construccin al principio de un programa se puede definir un nombre caracteres. Listado
// pascual.cpp // Emulacion del PASCAL mediante el preprocesador #include <iostream> using namespace std; #define PROGRAM int main() #define BEGIN { #define END return 0; } #define WRITE(A) cout << A PROGRAM BEGIN WRITE("Pascal en C++!!!"); END

simblico o constante simblica como una determinada cadena de

Salida
Pascal en C++!!!

El preprocesador remplaza todas las apariciones no entre comillas del nombre por su cadena correspondiente. Ejercicio Investigue todas las palabras reservadas del preprocesador, su sintaxis y un ejemplo de cada una. Constantes con nombre Para crear una constante con nombre se utiliza la palabra reservada const al declarar un objeto. Ejemplo:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

19

const int numero_constante = 10; const char caracter_constante = X; A las constantes no se les puede asignar valores despus de creadas as que se les asigna al momento de declararlas.

1.4 Objetos que permiten E/S por consola


El lenguaje C++ cuenta con una biblioteca estndar de objetos predefinidos para realizar diversas actividades, entre estos objetos se encuentran el "cin" y el "cout" para realizar entrada y salida por la consola. Objeto cout cout es el nombre de un objeto que representa la salida estndar a la consola (Console output/Salida en la consola). Ejemplo: cout << "Este es mi primer programa en C++"; Imprime en la salida estndar lo que esta entre comillas "Este es mi primer programa en C++". Los caracteres << son para simular una flecha la cual indica que lo que sigue va para la salida estndar. Un mensaje en cada lnea, para controlar el cambio de lnea se manda imprimir la palabra endl, que es un acrnimo de end line fin de lnea-.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

20

Listado
// control.cpp // utilizacin del objeto cout con el endl #include <iostream> using namespace std; int main() { cout << "Ahora vamos a controlar" << endl; cout << "el cambio de linea "; cout << "para dominar" << endl << "los mensajes"; cout << endl << endl << endl << "Y DESPUES EL C++..."; return 0; }

Salida
Ahora vamos a controlar el cambio de linea para dominar los mensajes

Y DESPUES EL C++...";

cout << "Ahora vamos a controlar" << endl; La palabra endl despus de los caracteres << indica un salto de lnea despus de imprimir el mensaje. cout << "para dominar" << endl << "los mensajes"; cout << endl << endl << endl << "Y DESPUES EL C++..."; El endl se puede incluir en cualquier parte despus de los caracteres << y tantas veces como sea necesario. Nota: Las siguientes lneas producen la misma salida: cout << Hola a todos;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

21

cout << Hola << a << todos; Objeto cin cin es un el nombre de un objeto que representa la entrada estndar (Console INput/Entrada en la consola), por omisin el teclado de una computadora. Ejemplo: cin >> fDolares Ingresa una entrada de datos de la entrada estndar y lo almacena en la variable fDolares. Los caracteres >> son para simular una flecha la cual indica que lo que sigue va de la entrada estndar hacia una variable. El objeto cin, como la mayora de los objetos cuenta con mtodos (Se estudian en el siguiente captulo) que se pueden llamar. Ejemplo: cout << Presione ENTER para continuar; // Ignora el ultimo ENTER ledo, que puede estar en el buffer de entrada cin.ignore(1, '\n'); cin.get(); // espera por un ENTER

El cdigo anterior detiene la ejecucin hasta que el usuario presione la tecla ENTER.

1.5 Operadores
Lo operadores son utilizados para realizar operaciones matemticas, lgicas y/o de relacin. Operadores aritmticos Operador + Accin Resta y menos unario Suma

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

22

* / % -++ += -= *= /=

Multiplicacin Divisin Modulo de divisin Decremento en uno Incremento en uno Incremento y asignacin Resta y asignacin Multiplicacin y asignacin Divisin y asignacin

Operadores ++ y -Lo mas comn al utilizar estos operadores es aplicarlos dentro de una sentencia de una sola variable, en este caso no importa el orden del operador, ya sea en forma prefija o pos fija actan de la misma manera, incrementa o decrementa en uno segn sea el caso. Ejemplo: i++; Es equivalente a: i = i + 1; Prefijo y posfijo de los operadores ++, -Los operadores ++ y actan diferente dependiendo de la forma en que se usen, prefija o postfija Ejemplo: n = i++; Es equivalente a: n = i; i = i +1;

n = ++i;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

23

Es equivalente a: i = i +1; n = i; Al usar la forma de prefijo la variable se incrementa o decrementa antes de ser usada; en la forma pos fijo la variable primero se usa y despus se incrementa o decrementa segn sea el caso. Listado
// mas_mas.cpp // Desmostracion del operador unario ++ #include <iostream> using namespace std; int main() { int i; i = 10; i++; cout << "i = " << i; cout << "\nSalida en posfija de i++ = " << i++; cout << "\n\nSalida de i = " << i; cout << "\nSalida prefija de ++i = " << ++i; return 0; }

Salida
i = 11 Salida en posfija de i++ = 11 Salida de i = 12 Salida prefija de ++i = 13

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

24

Operadores relacionales Operador > >= < <= == != Accin mayor que mayor que o igual que menor que menor que o igual que Igual no igual

Nota: El doble signo igual == es la notacin de C++ para "es igual a". Este smbolo se distingue de la condicin de igualdad del simple = empleado en las asignaciones.

Operadores lgicos Operador && || ! Accin and or not

Precedencia y orden de evaluacin de operadores Existen reglas de precedencia y orden de evaluacin de operadores para cuando estos se mezclan en una misma sentencia. Operador () [] -> . ! ~ ++ -- - * & sizeof */% +<< >> < <= > >= == != & Asociatividad Izquierda a derecha Derecha a izquierda Izquierda a derecha Izquierda a derecha Izquierda a derecha Izquierda a derecha Izquierda a derecha Izquierda a derecha

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

25

^ | && || ?: = += -= *= /= ,

Izquierda a derecha Izquierda a derecha Izquierda a derecha Izquierda a derecha Derecha a izquierda Izquierda a derecha Derecha a izquierda

1.6 Tipos de datos


Los tipos de datos sirven para declarar lugares de almacenamiento durante la ejecucin del programa, dependiendo del tipo de dato utilizado es lo que podemos almacenar.

1.6.1 Tipos de datos fundamentales


Los tipos bsicos y ms usados en un programa de C++ son: Tipo char Se utiliza para almacenar caracteres Descripcin Un tipo de dato especfico para manejo de caracteres de 8 bits de rango igual a -128 a int enteros 127. Tipo de dato entero con signo de 16, 32 64 bits, dependiendo del compilador. En sistemas de 16 bits su rango de valores es de -32763 a 32762. Para sistemas de 32 bits el rango se de -2147483648 a 2147483647. En sistemas de 64 bits el rango ser de 1.7+/-308. long float enteros largos flotante, nmero con fraccin Nmero real de 32 bits cuyo rango v de 3.4+/-38. Generalmente su precisin es de 7 dgitos.
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 26

double flotante, nmero con fraccin void indica que nada o indefinido Nota:

Nmero de 64 bits y de rango igual a 1.7+/308 con una precisin en general de 15 dgitos.

Para saber exactamente cuantos bytes estn disponibles para un determinado tipo de dato en el compilador que se este usando, se puede usar la funcin sizeof. Ejemplo: cout << sizeof(char); Imprime el nmero de bytes usados por el tipo de datos char.+

Listado
// condolar.cpp // Demuestra la declaracin de variables // as como la entrada y salida de datos // Convierte dolares a pesos #include <iostream> using namespace std; int main(){ float iPesos, fDolares; cout << endl << "Cuantos dolares desea convertir a pesos? "; cin >> fDolares; iPesos = fDolares * 12.5; cout << "Pesos = " << iPesos; return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

27

Salida en base a la entrada de ejemplo


Cuantos dolares desea convertir a pesos? 9 Pesos = 112.5

float iPesos, fDolares; Se declaran dos variables de tipo punto flotante, para almacenar nmeros con parte fraccionaria, nmeros como 3.1416, 2.5 y 1234, este ltimo es un nmero entero pero es almacenado como 1234.00. Nota: Tambin se puede declarar cada variable en una lnea separada: float iPesos; float fDolares; Para guardar un nmero entero; nmeros sin parte faccionaria como 5, 100 y 15 pero no 3.14 seria: int pesos;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

28

Ejercicios 1. Modifique el programa condolar.cpp, para que pida el tipo de cambio. 2. Realice un programa que calcule el rea de un tringulo. 3. Escriba un programa que calcule el rea de un cuadrado.

Modificadores de tipo Excepto para void, los tipos de datos bsicos tienen varios modificadores que los proceden. Se usa un modificador para alterar el significado de un tipo base para encajar con las necesidades diversas mas precisamente. En otras palabras estos modificadores de tipos combinados con los tipos de datos fundamentales dan paso a diferentes tipos de almacenamiento. Modificador de Tipo Signed Unsigned Descripcin Forza al compilador a utilizar un tipo de dato con signo si antes se declar como de tipo unsigned. Se aplica a los tipos de datos enlistados arriba, su efecto es eliminar el signo a el tipo de dato aplicado, por ejemplo, para un tipo de dato int podemos especificar unsigned int en cuyo caso el rango para el tipo de dato int cambia de ser -2147483648 a 2147483647, por ste long Short Volatile nuevo rango: 0 a 4294967295. Un nmero entero de 32 bits de rango igual a -2147483648 a 2147483647. Un nmero de 16 bits de rango igual a -32763 a 32762. Especfica una variable que almacena datos cuyo contenido puede cambiar en cualquier momento sea por la accin del programa como reaccin de la interaccin Auto Register Extern del usuario con el programa. Es lo mismo que si no se usara ningn modificador El compilador procurar almacenar la variable cualificada de este modo en un registro de la CPU. La variable se considera declarada en otro fichero. No se

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

29

Static

le asignar direccin ni espacio de memoria. Cuando se invoca a una funcin por segunda vez se pierden los valores que las variables locales de la funcin tenan al acabar la anterior llamada. Declarando una variable de este tipo cuando se llama por segunda vez a la subrutina la variable static (esttica) contiene el mismo valor que al acabar la llamada anterior.

Conversiones de tipo Cuando se mezclan constantes y variables de diferentes tipos en una expresin, C++ las convierte en el mismo tipo. El compilador de C++ convertir todos los operandos al tipo del operando mas grande en una operacin segn la base de esta operacin. Reglas de conversin de tipos 1. Todos los char y short int se convierten a int. Todos los float a double 2. Para todo par de operandos, lo siguiente ocurre en secuencia: Si uno de los operandos es long double, el otro se convierte a long double. Si uno de los operandos es double el otro se convierte a double Si uno de los operandos es long, el otro se convierte a long. Si uno de los operandos es unsigned, el otro se convierte a unsigned. Despus de que el compilador aplique estas reglas de conversin, cada par de operandos ser del mismo tipo, y el resultado de la operacin ser del tipo de los operandos. Ejemplo: char c; int i; float f; c = 65;
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 30

i = 10; f = i + c; La variable c se convierte a int al hacer la suma i + c, al realizar la asignacin el resultado de la suma se convierte a flota. Construccin cast Se usa para forzar la conversin explcita de tipos de datos. Listado
// lconst.cpp // Ejemplo de constantes literales #include <iostream> using namespace std; int main(){ cout << endl << 1/2; cout << endl << 1.0/2; cout << endl << float(1)/2; return 0; }

Salida
0 0.5 0.5

Nota: En la ltima lnea se usa la construccin cast para forzar la conversin explcita del tipo de dato.

Ejercicio

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

31

Quite la construccin cast (Sustituya la lnea: cout << endl << float(1)/2; por
cout << endl << 1/2;)

ejecute el programa y discuta con sus compaeros la

salida del programa modificado.

1.6.2 Tipos de datos definidos por el usuario


Los tipos definidos por el usuario es la creacin de un tipo de dato mediante la combinacin de los tipos de datos existentes y se definen como uniones, enumeraciones, tipos definidos (typedef), estructuras o clases. Las estructuras y uniones son tipos de clase (El tipo clase class- se estudia brevemente en el capitulo 3 y extensamente en el capitulo 4). Uniones Una unin es una localidad de memoria la cual es usada por dos o ms variables diferentes; generalmente de tipos diferentes. Cuando una unin es declarada, el compilador crea una variable de la longitud de la variable mayor definida en la unin. Solo un dato puede estar activo en un momento determinado de la lista de datos que formen la unin. Forma general: union etiqueta { tipo nombre_de_variable; . . . tipo nombre_de_variable; } variable_union; Ejemplo: union int_char { int i; char c; };
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 32

union int_char dosv; En la unin dosv, las 2 variables el int y el char comparten la misma localidad de memoria, el dato int ocupa toda la memoria disponible y el dato char solo una parte. Para acceder a una variable de la union se utiliza el operador de acceso . o > segn sea el caso (-> para punteros, estos sern estudiados en el capitulo 3): Ejemplo: dosv.c = x;

fig 4. Ejemplo de la comparticion de memoria usada por la unin en una maquina de 16 bits.

Uniones annimas Las uniones annimas son aquellas que no tienen etiqueta y no se utilizan para nombrar un objeto. Forma general: union { tipo nombre_de_variable; . . . tipo nombre_de_variable; };

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

33

Sus miembros pueden ser accedidos directamente en el mbito de su declaracin sin necesidad de usar ninguno de los operadores de acceso x.y o p->y. Listado
// union.cpp // Ejemplo de union con etiqueta y union anonima #include <iostream> using namespace std; int main(){ union { float f; char c; }; union int_char { int i; char c; }; int_char dos_var; c = 'X'; dos_var.c = 'Y'; cout << dos_var.c << "\t" << c << endl; return 0; }

Salida
Y X

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

34

Enumeraciones Una enumeracin es un conjunto de nombres de constantes enteras las cuales especifican todos los valores legales que debe tener un tipo de variable. Forma General: enum nombre {lista de enumeracin} lista_variables;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

35

Typedef Declara identificadores que se pueden utilizar para dar nombres a tipos de datos bsicos o derivados excepto funciones. El identificador se transforma en el equivalente sintctico a una palabra reservada. Forma general: typdef nombre_tipo; Ejemplo: Definicin de la palabra Entero: typedef int Entero; Uso: Entero n;

Estructuras Una estructura es un mtodo lgico de organizar datos y funciones (ver capitulo de funciones). La estructura es un patrn a seguir para crear variables de tipo estructura. Al definir una estructura se crea un tipo de dato definido por el usuario, y este tipo sirve para crear instancias de este tipo de dato. Se puede ver como un conjunto de una o ms variables, posiblemente de tipos diferentes, agrupadas bajo un mismo nombre. Principalmente se usa para organizar datos y esta parte es la que se describe a continuacin. Forma general: struct etiqueta { tipo nombre_variable; tipo nombre_variable; . . tipo nombre_variable; } variables_de_estructura;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

36

Para acceder a los elementos de la estructura: nombre_estructura.nombre_elemento

Listado
// structFecha.cpp // Estructuras #include <iostream> using namespace std; // definicion de la estructura (tipo) struct Fecha { int dd; int mm; int aa; }; int main() { Fecha fecha; // Declaracion de una variable de tipo estructura

cout << "Numero de dia "; cin >> fecha.dd; cout << "Numero de mes "; cin >> fecha.mm; cout << "A#o "; cin >> fecha.aa; cout << fecha.dd << "/" << fecha.mm << "/" << fecha.aa; return 0; }

Salida
Numero de dia 24 Numero de mes 12 A#o 2010 24/12/2010

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

37

struct Fecha { int dd; int mm; int aa; }; Estas lneas definen la estructura, aqu solo se crea el tipo de dato definido por el usuario llamado Fecha. Fecha fecha; Se declara la variable fecha del tipo Fecha, que es del tipo de estructura definida anteriormente. cin >> fecha.dd; Se ingresa desde la entrada estndar, un valor y se le asigna al elemento entero dd que es parte de la variable fecha.

1.7 Palabras reservadas


Las palabras reservadas son identificadores utilizados por el lenguaje para fines especiales, y no pueden ser utilizadas para por ejemplo nombrar variables, clases, funciones, etc. La siguiente tabla contiene las palabras reservadas del lenguaje divididas en las palabras que provienen del lenguaje C, las que cambiaron su significado al trasladarse al C++, y las exclusivas de C++. Lenguaje C Auto Break case char const De C sobrecargadas en C++ Struct Static Const enum Lenguaje C++ and and_eq asm bitand bitor

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

38

continue default Do double else enum extern float for goto If int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

bool catch class compl const_cast delete dynamic_cast explicit export false friend inline mutable namespace new not not_eq operator or or_eq private protected public reinterpret_cast static_cast template this throw true try typeid typename usin virtual w_char xor xor_eq

1.8 Expresiones
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 39

Una expresin es una secuencia de operadores y operandos que especifica un calculo. Una expresin puede dar como resultado un valor y puede originar efectos secundarios (efectos colaterales) (Ellis/Stroustrup 1994) Sintaxis de las expresiones C++ Las expresiones son definidas recursivamente, de forma que las subexpresiones pueden ser anidadas sin ningn lmite formal, aunque quizs el compilador pueda reportar un error de lmite de memoria si no puede compilar una expresin muy compleja.

1.9 Estructuras de Control


Las estructuras de control determinan el flujo de ejecucin de las instrucciones, mediante estas estructuras se puede controlar en orden y las veces que se ejecutan las instrucciones.

1.9.1 Asignacin
El hecho que las expresiones sean definidas recursivamente permite por ejemplo la asignacin mltiple. Ejemplo: int x, y, z; x = y = z = 0; Todas las variables se inicializan a cero.

1.9.2 Seleccin
C++ cuenta con dos tipos de tratamiento de condiciones, para condiciones de cierto / verdadero y para condiciones mltiples.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

40

if-else
Permite seleccionar la ejecucin de dos bloques de cdigo mediante la evaluacin de una condicin. Forma general 1: if (expresin) bloque de cdigo; Si la expresin es verdadera se ejecuta el bloque de cdigo, si la expresin es falsa no se ejecuta el bloque de cdigo. Forma general 2: if (expresin) bloque de cdigo 1; else bloque de cdigo 2; Si la expresin es verdadera se ejecuta el bloque de cdigo 1, si la expresin es falsa se ejecuta el bloque de cdigo 2. Donde expresin: a) variables de tipo boolean b) operacin con operadores aritmticos, lgicos y/o relacinales Donde bloque de cdigo: a) una sola instruccin b) { varias instrucciones } Listado // adivina.cpp // Ejemplo if..else // juego de adivina el numero que la computadora genera aleatoriamente

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

41

#include <iostream> #include <ctime> using namespace std; int main() { int n, pc; srand( (unsigned)time( NULL ) ); pc = rand() % 5; cout << "\nAdivina el numero que pienso (0-4) " << endl; cin >> n; if (n == pc) cout << "Adivinaste!"; else cout << endl << "Intenta otra vez"; return 0; } Salida en base a la entrada de ejemplo
Adivina el numero que pienso (0-4) 2 Intenta otra vez

#include <ctime>; ctime es para usar la funcin time() para plantar la semilla de la funcin rand(). srand( (unsigned)time( NULL ) );

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

42

La funcin srand, se usa para plantar la semilla de los nmeros aleatorios usando el tiempo regresado por la funcin time(), el NULL dentro de time() es para que agarre el tiempo actual. pc = rand() % 5; rand(), genera el nmero aleatorio, el % 5, le dice que genere un numero en un rango de 5 nmeros, desde el 0 hasta el 4. En el resto del cdigo se lee un nmero de la entrada y lo compara con el nmero generado en forma aleatoria, if (n == pc), en caso que la evaluacin sea verdadera despliega Adivinaste! de lo contrario despliega Intenta otra vez. Los bloques a seleccionar mediante la condicin estn compuestos solo por una lnea y mediante el punto y coma el compilador sabe exactamente cual bloque pertenece a la parte del if y cual a la del else. Note que al final de la comprobacin de la condicin del if este no tiene un punto y coma sino hasta el final de la sentencia: if (n == pc) cout << "Adivinaste!"; Igual pasa con la sentencia else, el punto y coma esta al finalizar la lnea que va a ejecutarse en caso de que la condicin hecha en el encabezado del if no se cumpla: else cout << endl << "Intenta otra vez"; En caso de que el bloque a ejecutar al hacerse la seleccin se componga de mas de una lnea de cdigo hay que indicarle al compilador donde empieza este bloque mediante el uso de la llave que abre { y tambin donde termina el bloque de instrucciones utilizando la llave que cierra }.
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 43

Ejemplo: if (n == pc) { cout << "Adivinaste!" << endl; cout << "\t\tTienes poderes siquicos?" << endl; } else { cout << endl << "No le atinaste"; cout << endl << "\t\tIntenta otra vez"; } Otras combinaciones pueden ser por ejemplo: if (n == pc) { cout << "Adivinaste!" << endl; cout << "\t\tAcaso tienes poderes siquicos?" << endl; } else cout << endl << "Intenta otra vez"; Tambin: if (n == pc) cout << "Adivinaste!" << endl; else { cout << endl << "No le atinaste"; cout << endl << "\t\tIntenta otra vez"; } Las llaves de inicio y fin de bloque se pueden usar aunque sea solo una sentencia, por ejemplo lo siguiente es perfectamente valido:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

44

if (n == pc) { cout << "Adivinaste!" << endl; } else { cout << endl << "Intenta otra vez"; } En el siguiente fragmento de cdigo el else no tiene llaves, por lo tanto el bloque de instrucciones perteneciente al else es de una sola lnea: if (n == pc) { cout << "Adivinaste!" << endl; cout << "\t\tAcaso tienes poderes siquicos?" << endl; } else cout << endl << "No le atinaste"; cout << endl << "\t\tIntenta otra vez"; La ultima lnea en este fragmento de cdigo no pertenece al else, esta lnea siempre se ejecuta no importa si se cumple la condicin del if o no; lo nico que tiene es la sangra y a simple vista pudiera parecer que pertenece al cuerpo del else. En el siguiente ejemplo el bloque de cdigo perteneciente al if es de una sola lnea ya que no tiene llaves: if (n == pc) cout << "Adivinaste!" << endl; cout << "\t\tAcaso tienes poderes siquicos?" << endl; else {

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

45

cout << endl << "No le atinaste"; cout << endl << "\t\tIntenta otra vez"; } El if se compone realmente por: if (n == pc) cout << "Adivinaste!" << endl; La lnea que le sigue est fuera del if: cout << "\t\tAcaso tienes poderes siquicos?" << endl; El else no forma parte del if porque este termino con el punto y coma, por lo tanto marca un error de sintaxis por el compilador ya que else solo puede ir acompaado de un if. else { cout << endl << "No le atinaste"; cout << endl << "\t\tIntenta otra vez"; } Al mostrar el prrafo de cdigo anterior con sangra se aprecia mas el error (otra razon del porque utilizar sangras) if (n == pc) cout << "Adivinaste!" << endl; cout << "\t\tAcaso tienes poderes siquicos?" << endl; else { cout << endl << "No le atinaste"; cout << endl << "\t\tIntenta otra vez"; } Ejercicios

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

46

1.

Modifique el programa condolar.cpp, para presentarle al usuario la opcin de convertir de dolares a pesos y de pesos a dlares, realice la operacin seleccionada por el usuario.

2.

Realice un programa que lea un nmero de la entrada estndar y despliegue si el nmero ledo es par o impar, utilice el operador % para obtener el residuo de la divisin, note que el residuo de una divisin entre dos de un nmero par siempre es cero.

Evaluacin de la expresin En C++ la evaluacin de la expresin dentro de los parntesis despus del if, para que sea verdadera debe ser distinta de cero y es falsa cuando es cero. Ejemplo: if (1) cout << Expresion verdadera; // <-- se imprime esto en pantalla if (0) cout << Expresion verdadera; else cout << Expresion falsa; // <-- se imprime esto en pantalla El lenguaje C++ no pone restriccin al tipo de expresiones a solo las que invocan operadores relacionales y lgicos. Todo lo que se requiere es que la expresin evaluada de cero o no cero. Listado
// divide.cpp // Divide el primer numero por el segundo #include <iostream> using namespace std; int main() { float a, b;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

47

cout << endl << "Introduce dos numeros enteros: "; cin >> a >> b; if (b) // equivalente a (b != 0) cout << a/b << endl; else cout << "No puedo dividir por cero" << endl; return 0; }

Salida en base a la entrada de ejemplo


Introduce dos numeros enteros: 3 0 No puedo dividir por cero

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

48

if (b) Evala si la variable es distinta de cero (verdadero) o cero (falso) if anidado Se le llama if anidado cuando un bloque de cdigo perteneciente a un if-else contiene otro if o if-else. Listado
// mayor.cpp // compara dos numeros y dice si son iguales o cual es el mayor #include <iostream> using namespace std;

int main(){ int a, b; cout << "\nDame un numero "; cin >> a; cout << "Dame otro numero "; cin >> b; if (a == b) cout << "Los numero son iguales"; else if (a > b) cout << "El numero " << a << " es mayor que " << b; else cout << "El numero " << b << " es mayor que " << a; return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

49

Salida en base a la entrada de ejemplo


Dame un numero 12 Dame otro numero 3 El numero 12 es mayor que 3

if (a == b) cout << "Los numero son iguales"; else if (a > b) cout << "El numero " << a << " es mayor que " << b; else cout << "El numero " << b << " es mayor que " << a; El segundo if se encuentra dentro del bloque de cdigo perteneciente al else, ambos if tienen la parte del else, cuando esto no sucede se puede prestar a confusiones. Ejemplo: if (a != b) if (a > b) cout << "El numero " << a << " es mayor que " << b; else cout << "El numero " << b << " es mayor que " << a; En esta situacin el ltimo else pertenece al if inmediato anterior. if (a != b) if (a > b) cout << "El numero " << a << " es mayor que " << b; else cout << "numeros iguales ";

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

50

Aqu aunque el else este alineado con el primer if, este sigue perteneciendo al if inmediato anterior, para lograr que el else pertenezca al primer if se necesita utilizar las llaves de inicio y fin de cdigo. if (a != b) { if (a > b) cout << "El numero " << a << " es mayor que " << b; } else cout << "numeros iguales ";

switch La sentencia switch es usada para decisiones mltiples que comprueba si una expresin iguala uno entre varios valores constantes. Forma General: switch (variable) { case constante1: bloque de cdigo; case constante2: bloque de cdigo; break; . . . default: bloque de cdigo; } Descripcin

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

51

1. El switch difiere del if porque la primera solo puede comprobar por igualdad, mientras que la expresin condicional del if puede ser de cualquier tipo. 2. No pueden tener dos constantes case con idnticos valores en el mismo switch. Una sentencia switch que esta encerrada por otro switch puede tener constantes case que son las mismas. case Acta como una etiqueta. break Opcional dentro de la sentencia switch. Se usa para terminar la secuencia que esta asociada con cada constante. Si se omite, la ejecucin continuara en las sentencias del siguiente case hasta encontrar un break, un return o el final del switch. default Es opcional y se ejecuta si no se satisface ninguna opcin. Listado
// fechaSwitch.cpp // demostracion del switch #include <iostream> using namespace std; int main(){ int iMes = 9; cout << iMes << " "; switch(iMes) { case 1: cout << "enero"; break; case 2:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

52

cout << "febrero"; break; case 3: cout << "marzo"; break; case 4: cout << "abril"; break; case 5: cout << "mayo"; break; case 6: cout << "junio"; break; case 7: cout << "julio"; break; case 8: cout << "agosto"; break; case 9: cout << "septiembre"; break; case 10: cout << "octubre"; break; case 11: cout << "noviembre"; break; case 12: cout << "diciembre"; break; default: cout << " *error*"; } return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

53

Salida
9 septiembre

int iMes = 9; La variable mes es inicializada al momento de declararla, al entrar al switch este compara la variable iMes con las constantes literales en los cases hasta encontrar el case 9: y se ejecuta la lnea debajo de este desplegando septiembre, a continuacin se ejecuta la siguiente lnea conteniendo la instruccin break la cual rompe el switch. En caso que la variable no se encuentre en ninguno de los case, se ejecuta la sentenciaque le sigue a default. Note el uso del break al terminar cada case, esto es necesario para que termine la ejecucin del switch y no continu con los siguientes case, lo cual es til en algunas situaciones, como en el siguiente programa por ejemplo. Listado
// switch_dolar.cpp // Convierte dolares a pesos o viceversa, pide el tipo de cambio // ejemplo del switch con las clasusulas case sin el break #include <iostream> using namespace std; int main(){ char opcion; float dolares, pesos, cambio; cout << "Cual es el tipo de cambio? "; cin >> cambio; cout << "*** M E N U ***" << endl << "ingrese la primera letra de la palabra"

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

54

<< endl; cout << "D olares a pesos" << endl; cout << "P esos a dolares" << endl; cout << "Opcion? "; cin >> opcion; switch (opcion) { case 'd': case 'D': cout << endl << "Cuantos dolares desea convertir a pesos? "; cin >> dolares; pesos = dolares * cambio; cout << "Pesos = " << pesos; break; case 'p': case 'P': cout << endl << "Cuantos pesos desea convertir a dolares? "; cin >> pesos; dolares = pesos / cambio; cout << "Pesos = " << dolares; break; default: cout << "opcion no implemenrada"; } return 0; }

Salida en base a la entrada de ejemplo


Cual es el tipo de cambio? 12.5 *** M E N U *** ingrese la primera letra de la palabra D olares a pesos P esos a dolares Opcion? d Cuantos dolares desea convertir a pesos? 18

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

55

Pesos = 225

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

56

case 'd': case 'D': cout << endl << "Cuantos dolares desea convertir a pesos? "; cin >> dolares; pesos = dolares * cambio; cout << "Pesos = " << pesos; break; El case d: no contiene un break (ni cdigo) por lo tanto si el usuario del programa ingresa una d minscula entra a este case continua hacia abajo y se ejecuta el cdigo del case con la D mayscula, el cuerpo de este case tiene un break porque no debe ejecutar lo que esta en el siguiente case. Ejercicios
1. 2.

Modifique el programa fechaSwitch.cpp para que pida el mes del teclado Escriba un programa que lea un carcter del teclado y si se trata de un nmero despliegue el nmero con letra, si no es un nmero mencionarlo, utilize la sentencia switch. Discuta la posibilidad de hacer un programa que escriba su nombre completo 100 veces; 10,000 veces?; 9,000,000 de veces?

3.

1.9.3 Iteracin
Las sentencias de repeticin permiten ejecutar una porcin de cdigo varias veces. do-while Hace la comprobacin al final despus de cada pasada a travs del cuerpo del ciclo. Y este se ejecuta al menos una vez. Forma general: do bloque de cdigo; while (expresin);
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 57

Listado
// doadivina.cpp // do..while, adivina el numero generado aleatoriamente // Termina cuando el usuario as lo desea #include <iostream> #include <ctime> using namespace std; int main() { int n, pc; char c; srand( (unsigned)time( NULL ) ); pc = rand() % 5; do { cout << "\nAdivina el numero que pienso (0-4) " << endl; cin >> n; if (n == pc) cout << "ADIVINASTE!!!" << endl; else cout << "NO ES!!!" << endl; cout << endl << "Intenta otra vez? (s/n)"; cin >> c; } while (c != 'n'); return 0; }

Salida en base a la entrada de ejemplo


Adivina el numero que pienso (0-4) 1 NO ES!!! Intenta otra vez? (s/n)s

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

58

Adivina el numero que pienso (0-4) 3 ADIVINASTE!!! Intenta otra vez? (s/n)n

Este es el ejemplo adivina.cpp presentado en el listado 2.1, pero dentro de un ciclo. do { Inicia el ciclo, lnea 14, en la lnea 22 y 23 pregunta si se quiere continuar intentando. } while (c != 'n'); En la lnea 24, checa lo que se ley en la variable c y la compara, con en caso que sea verdadera la evaluacin el ciclo termina, de lo contrario regresa al do {. Ejercicios
1.

Modifique el programa switch_dolar.cpp, que lee un carcter del teclado y si se trata de un nmero despliega el nmero con letra y si no es un nmero lo menciona para que termine hasta que se ingrese una 'X'.

2. Discuta como se puede mejorar el ejemplo anterior (doadivina.cpp), por ejemplo, que sucede si el usuario adivina el nmero y desea seguir jugando?, realice las modificaciones sugeridas. 3. Hacer un programa que escriba su nombre completo 10,000 veces

while Hace la comprobacin al inicio de cada pasada a travs del cuerpo del ciclo. Si la evaluacin es falsa no se ejecuta ni una sola vez. Forma general:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

59

while (expresin) bloque de cdigo; Listado


// ascii.cpp // Despliega la tabla Ascii en la salida estndar #include <iostream> using namespace std; int main() { int i; i = 0; while (i < 256) { // el caracter 26, puede borrar pantalla cout << char(i) << " i++; } return 0; } " << i << " ";

Salida

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

60

while (i < 255) { Se evala la variable i si es menor a 255 empieza el ciclo y se ejecuta la primera sentencia despus de la llave { as sucesivamente hasta que se encuentra la llave que cierra } al pasar esto, se evala la condicin dentro de los parntesis del while si la i todava es menor a 255 vuelve a ejecutar una por una las instrucciones dentro de las llaves { y }, cuando la variable i sea igual a 255 el ciclo termina. La instruccin char(i), regresa el carcter ASCII correspondiente al entero de la variable i. for Forma general: for (inicializacin; condicin; incremento) bloque de cdigo;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

61

Gramaticalmente, los tres componentes de un for son expresiones. Mas comnmente, inicializacin e incremento son asignaciones o llamadas a funcin y condicin es una expresin de relacin. Puede omitirse cualquiera de las tres partes, aunque deben permanecer los puntos y comas. Ejemplo: for (; ;) ; Este es un ciclo infinito; que podramos terminar con un break o con un return. La proposicin for es equivalente a: inicializacin; while (condicin) { bloque de cdigo; incremento; } Listado
// for_prom.cpp // ejemplo del for el promedio de la suma de 5 nmeros #include <iostream> using namespace std; int main() { float fCalificacion, fSuma, fPromedio; int i; cout << "Ingresa calificaciones " << endl; fSuma = 0; for (i = 0; i < 5; i++) { cout << i << ". Calificacion? "; cin >> fCalificacion; fSuma = fSuma + fCalificacion;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

62

} fPromedio = fSuma / 5; cout << endl << "El promedio es " << fPromedio; return 0; }

Salida en base a la entrada de ejemplo


Ingresa calificaciones 0. Calificacion? 100 1. Calificacion? 95 2. Calificacion? 90 El promedio es 95

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

63

for (i = 0; i < 5; i++) { Inicia el ciclo for ejecutndose primero la parte de inicializacin i = 0; despus se evala i < 5; la primer a vez se cumple la condicin y entra al cuerpo del for, en el cuerpo del for (todas las sentencias que estn en medio de la llave que abre { que le sigue al for y la llave que cierra } correspondiente) se pide la calificacin y se acumula en fSuma. Al terminar el cuerpo del for regresa a la lnea 12 e incrementa i++ despus evala i < 5, si la evaluacin es verdadera vuelve al cuerpo del for si no es as termina (ntese que despus de la primera vez que se ejecuta el for, ya no se realiza la parte de inicializacin y el encabezado del for se evala de derecha a izquierda) fPromedio = fSuma / TAM; En la lnea 17 se calcula el promedio y lo despliega en la siguiente lnea. Ejercicios
1.

Modifique programa ejemplo for_prom.cpp para que utilice la iteracin while en vez del for. Modifique el programa ejemplo ascii.cpp para que utilice la iteracin for en vez del while (asciifor.cpp) .

2.

3. Discuta la posibilidad de hacer un programa a) Que almacene 3 nmeros y los despliegue en orden de menor a mayor b) Que almacene 100 nmeros y los despliegue en orden de menor a mayor

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

64

Capitulo 2
Subprogramas

2.1 Definicin de un subprograma


En C++ un programa puede crearse como un grupo de bloques, donde cada bloque contiene cdigo lo ms independiente posible y comprobable llamado subprograma. Los subprogramas contienen entradas y salidas para conectarlos a otros bloques de cdigo subprogramas- para formar el programa principal. La divisin de un programa en subprogramas es parte de una tcnica de programacin llamada programacin modular; la cual es basada en la filosofa de divide y vencers.
Mdulos Un modulo es un conjunto encapsulado de datos y operaciones que tienen relacin entre si. En el caso de C++ lo comn es que sea en un archivo de encabezado y en un archivo de implementacin. La utilizacin de mdulos es para formar partes de cdigo independiente con el propsito de reducir la complejidad, aumentar y facilitar la reutilizacin del cdigo adems de hacer ms

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

58

mantenible los programas. La modularidad es la capacidad de dividir el problema en pequeas partes independientes entre si [Hernandez 2002]

fig1. Organizacin de programas mediante mdulos

2.1.1 Estructura de un subprograma


Un subprograma se implementa en C++ mediante funciones. Una funcin es una o ms instrucciones en designadas para una tarea especifica, a este conjunto de instrucciones se le asigna un nombre, que identifica la funcin dentro del programa.
Los programas en C++ cuentan con una funcin especial llamada main() esta es llamada automticamente al iniciar la ejecucin del programa; dentro de esta funcin se realizan llamadas a objetos y/o otras funciones. El cdigo de una funcin es privado a la funcin y no puede ser accesado por ninguna declaracin en ninguna otra funcin excepto a travs de argumentos y variables globales.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

59

Las variables definidas dentro de una funcin son variables locales dinmicas (empiezan a existir cuando la funcin es llamada y se destruyen al terminar). Forma general: especificador_tipo nombre_funcion(lista_de_argumentos) { cuerpo de la funcin <return valor> } La lista_de_argumentos es una lista de nombres de variables separados por comas que recibe los valores de los argumentos cuando se llama la funcin. El especificador_de_tipo es el tipo de valor que la funcin devuelve mediante el return.

2.1.2 Valor de retorno


Las funciones terminan cuando se encuentra la ltima llave o mediante la sentencia return y devuelven el control de flujo del programa automticamente al procedimiento que la llam. Listado // linea.cpp // Funcion que dibuja una linea de 40 guiones #include<iostream> using namespace std; void linea() { int i; for (i = 0; i < 40; i++) cout << "-"; } int main() { linea(); cout << endl << "Este mensaje es importante" << endl; linea(); return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

60

Salida ---------------------------------------Este mensaje es importante ----------------------------------------

void linea() linea es el nombre de la funcin, y void antes del nombre indica que esta funcin no va a regresar un valor al proceso que la llame, el parntesis que abre y el parntesis que cierra despus del nombre indican que es una funcin, entre estos parntesis se ponen los argumentos de la funcin, en este caso la funcin no necesita argumentos. linea() En la primera lnea de la funcin main se hace el llamado a la funcin definida anteriormente, note que aunque la funcin no recibe parmetros el uso de los parntesis es obligatorio.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

61

Nota: La funcin linea() esta definida antes de la funcin main() esto es para que el compilador ya la conozca cuando se haga la llamada dentro de main(), si se escribiera la funcin linea() abajo o en otro archivo, abra que poner la declaracin arriba del main(), ya sea escribindola directamente en el archivo principal o en un archivo de encabezado, mediante un #include.

2.2 Declaracin de un subprograma


La declaracin de un subprograma llamada en C++ prototipo de funcin se refiere a solo escribir el encabezado de la misma. Cuando la implementacin se codifica despus de que la funcin es llamada o en un archivo aparte de donde se manda llamar se debe incluir el encabezado de la funcin antes de que esta sea llamada, esto es para que el compilador verifique si la sintaxis con que se llam la funcin definida por el usuario es correcta. Decirle al compilador que la funcin existe y como es llamada [Eckel 1993] Listado
// proto_linea.cpp // Ejemplo de prototipo de funciones // Funcion que dibuja una linea de 40 guiones #include<iostream> using namespace std; void linea(); int main() { linea(); cout << endl << "Este mensaje es importante" << endl; linea(); return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

62

void linea() { int i; for (i = 0; i < 40; i++) cout << "-"; }

Salida ---------------------------------------Este mensaje es importante ----------------------------------------

2.3 Bibliotecas o librera de subprogramas


Las libreras son una manera de aadir funcionalidad al lenguaje sin agregar palabras reservadas al lenguaje, por ejemplo una funcin puede ser compilada y almacenada en una librera o archivo, de donde el encadenador la extrae. El proveedor del compilador generalmente proporciona bibliotecas estndar de funciones y clases. Los proveedores de software independientes proporcionan bibliotecas de propsito especial. Tipos de libreras En C++ existen dos tipos fundamentales de libreras: estticas y dinmicas. En ambos casos junto a las libreras (archivos con la extensin .lib, .a, .dll etc) se incluyen archivos "de cabecera", archivos con la extensin .h estos archivos contienen las declaraciones de las entidades contenidas en la librera, as como las macros y constantes predefinidas utilizadas en ella. Es decir, la "interfaz" de las funciones o clases que utilizar. En el caso de funciones esto se concreta en el prototipo; en el caso de clases, en la especificacin de sus mtodos y propiedades pblicas*. (http://www.zator.com/Cpp/E1_4_4b.htm)

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

63

Estticas Son tambin denominadas libreras-objeto, son colecciones de archivos objeto (compilados) agrupados en un solo archivo con la extensin .lib, .a, etc. junto con uno o varios archivos de cabecera (generalmente con la extensin .h). Los componentes utilizados de estas libreras quedan incluidos en el programa ejecutable. Dinmicas Son las denominadas libreras de enlazado dinmico, es decir los componentes utilizados se agregan cunado el programa se esta ejecutando y permite que la misma librera pueda ser usada por varios ejecutables sin necesidad que se embeba permanentemente en un solo archivo ejecutable. Generalmente conocidas como DLLs, acrnimo de su nombre en ingls ("Dynamic Linked Library"). Estas libreras se utilizan mucho en la programacin para el Sistema Operativo Windows. Listado // tolower.cpp // // Muestra el uso de la funcion tolower que convierte un caracter a minusculas

#include <iostream> using namespace std; int main() { char a, b, c; a = 'R'; b = tolower(a); cout << a << " " << b; cout << endl << "Ingrese una letra en Mayusculas "; cin >> c; b = tolower(c); cout << "Letra en minusculas " << b; return 0; } Salida Rr

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

64

Ingrese una letra en Mayusculas Q Letra en minusculas q

Ejercicio Modifique el programa doadivina.cpp del cap 1- para que acepte minsculas y maysculas cuando pregunta si desea continuar, utilice la funcin toupper().

Clase string
El tipo de dato string no existe en C++, este se implementa mediante tipo de dato definido por el usuario mediante una clase (esta clase se incluye en una de las libreras del C++ estndar proporcionadas por el compilador). Un string es una clase para declarar objetos y estos objetos contienen bsicamente una secuencia de caracteres. Los programas que usen la clase string deben incluir la sentencia using namespace std y el archivo de encabezado: #include <string> Listado // string1.cpp #include <iostream> #include <string> using namespace std; int main() { string strNombre; cout << "Cual es tu nombre? "; cin >> strNombre; cout << "\nSaludos " << strNombre << endl; cout << "\nTu nombre tiene " << strNombre.length() << " letras"; return 0; } Salida Cual es tu nombre? Batman

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

65

Saludos Batman Tu nombre tiene 6 letras

strNombre.length() Objeto strNombre llamando un metodo, la cual regresa cuantos caracteres tiene el string. Nota: Para ingresar oraciones (palabras con espacios intermedios) usar: getline(cin, str, \n); Donde str es un objeto de tipo string.

Ejercicio

Tome como base el ejemplo string1.cpp para hacer un programa donde declare 3 variables string s1, s2, s3
a) Asigne s1 y s2 con datos proporcionados por el usuario

b) Concatene s1 y s2 (s1 + s2 concatena los strings) dejando el resultado en s3 c) Despliegue el string s3

Nota: Algunos compiladores de C++ incluyen subprogramas que no son parte de las libreras estndar, esto facilita de alguna forma la programacin, pero limita la portabilidad del cdigo a otros compiladores y/o plataformas.

2.4 Primer acercamiento a clases y objetos


Programacin orientada a objetos El objetivo principal de la programacin orientada a objetos es facilitar las tareas de programar y reutilizar el cdigo, en una forma integrada y ms modular que la estructurada. Clase

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

66

Describe un conjunto de objetos los cuales tienen las mismas caractersticas (datos) y el mismo comportamiento (cdigo), una clase es realmente un tipo de dato definido por el usuario, es una extensin del concepto del tipo de dato registro, el cual nos permite organizar diferentes tipos de datos en un solo lugar. La clase nos permite combinar datos y cdigo dentro de un solo paquete. Objeto Un objeto es una instancia de una clase, la clase es el tipo de dato y el objeto es la variable. Un objeto tiene un estado, comportamiento e identidad. Una identidad porque cada objeto pose un nombre (identificador) nico, un estado porque los datos tienen un valor determinado dependiendo del proceso en que se encuentre el objeto, y un comportamiento porque sabe que hacer con esos datos, es decir tiene sus propios algoritmos para procesar sus datos.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

67

Listado // claseFecha.cpp // Clases #include <iostream> #include <string> using namespace std; class Fecha { public: int dd; string mm; int aa; }; main() { Fecha fecha; cout << "Dia "; cin >> fecha.dd; cout << "Mes en letra "; cin >> fecha.mm; cout << "A#o "; cin >> fecha.aa; cout << fecha.dd << " de " << fecha.mm << " de " << fecha.aa; }

Salida en base a la entrada de ejemplo


Dia 12 Mes en letra enero A#o 2009 12 de enero de 2009

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

68

2.5 mbito y tiempo de vida de variables


Alcance de variables
Los programas en C++ se forman a base de bloques de cdigo estos bloques inician con la llave { y terminan con la llave }. Las variables declaradas dentro de un bloque de cdigo son locales a ese bloque, no pueden ser accesadas por otro bloque o afuera de este.

Variables automticas, tambin llamadas locales dinmicas


Cada variable local comienza a existir cuando se ejecuta el bloque donde fue declarada y desaparece cuando el bloque de cdigo acaba. Estas variables no conservan su valor entre dos llamadas sucesivas.

Variables externas, tambin llamadas globales


Se definen fuera de las funciones, estas son externas a todas las funciones; esto es variables globales a las que puede acceder cualquier funcin mediante su nombre. Cuando son declaradas en otro archivo se debe usar la palabra reservada extern.

Listado
// alcance.cpp // Ejemplo de alcance de variables y del operador de alcance :: #include <iostream> using namespace std; int a = 0; int main() { int a = 10; cout << a << endl; cout << ::a << endl;

{ int x = 20; cout << x << endl; x++;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

69

} //cout << x; return 0; }

Salida
10 0 20

int a = 0; Declara una variable global, para todos los bloques de cdigo que le siguen hacia abajo, en este caso el bloque de main() que empieza y el bloque sin nombre que empieza abajo del segundo cout. int a = 10; Sobrescribe a la variable con el mismo nombre declarada anteriormente antes de empezar la funcin main(). El primer cout despliega el contenido de la variable local a. El segundo cout despliega el contenido de la variable global, utilizando el operador de alcance :: La llave que abre { despus del segundo cout indica el inicio de un bloque de cdigo sin nombre.

int x = 20; Declara una variable local para el bloque que inicio en la lnea anterior, la variable empieza a existir aqu y termina al cerrar el bloque con la llave que cierra }.
El ultimo cout esta como comentario porque marca un error, de variable no encontrada ya que la variable x dejo de existir al terminarse el bloque sin nombre.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

70

Espacio de nombres
Por omisin cuando un nuevo tipo de dato es definido este existe globalmente. Lo cual significa que est disponible a cualquier funcin en la aplicacin. Para evitar conflictos entre las diferentes libreras (mdulos de cdigo para ser rehusado), cada librera puede crear su propio bloque de espacio de definicin de datos, utilizando la palabra reservada namespace. namespace Un espacio de nombres definido por la palabra namespace es el alcance en el cual los tipos de datos pueden ser definidos para evitar la sobrecarga del espacio de alcance global. El uso de namespace permite agrupar un conjunto de variables globales dentro de un nombre. Es decir el alcance global se subdivide en espacios de nombres. Forma general: namespace identificador { cuerpo-del-namespace }

using namespace La directiva using seguida del namespace sirve para asociar el nivel en que un identificador esta con cierto namespace, para que los objetos, funciones y variables de ese namespace pueden ser accesibles directamente como si estuvieran definidos en el alcance global. Forma general: using namespace identificador;

Listado
// namespace.cpp #include <iostream> using namespace std; namespace espacio1 { int a = 0;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

71

}; namespace espacio2 { int a = 100; }; int main() { cout << "namespace espacio1 " << espacio1::a; cout << "\nnamespace espacio2 " << espacio2::a; return 0; } Salida namespace espacio1 0 namespace espacio2 100

En este ejemplo se utiliza el operador de alcance :: para especificar que espacio de nombre utilizar; para evitar poner el nombre cada vez que se use lo que esta definido en el espacio de nombres se puede utilizar using namespace.

2.6 Argumentos y paso de parmetros.


Hay tres tipos de argumentos para las funciones Por valor Por puntero* Por referencia* * Estos dos ltimos se estudian en el siguiente capitulo de Punteros, referencias y arreglos. Llamada por valor Este mtodo copia el valor del argumento dentro de los parmetros formales de la funcin y todos los cambios que sufran los parmetros no afectan el valor del argumento usado para llamar la funcin. Los parmetros formales de la funcin son las declaraciones de las variables que aceptan los valores de los argumentos.

Listado

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

72

// sqr.cpp // Usa una funcion que recibe y regresa un valor entero #include <iostream> using namespace std; int sqr(int num) { num = num * num; return num; } int main() { int n, x; cout << "Ingresa un numero "; cin >> n; x = sqr(n); cout << endl << "El cuadrado de " << n << " es " << x; return 0; }

Salida Ingresa un numero 3 El cuadrado de 3 es 9

int sqr(int num) { El primer int indica que la funcin regresa un valor de tipo entero y el segundo que recibe un entero como argumento. return num; Aqu se regresa el valor contenido en la variable num, el tipo de dato que se regrese con return debe de corresponder al tipo de dato que aparece antes del nombre de la funcin. El return puede aparecer en cualquier parte del cuerpo de la funcin e inmediatamente regresa el control a la lnea de donde fue llamada la funcin, devolviendo el valor indicado despus del

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

73

return en caso que exista tal valor ya que tambin puede estar solo y en ese caso solamente regresar el control a la parte de donde fue llamada. x = sqr(n); La funcin es llamada con n como argumento y regresa el nmero indicado en el return asignndoselo a la variable x. Ejercicios 1 2 3 Escriba una funcin que reciba un nmero y regrese su valor absoluto. Realice una funcin eleva(n, x) que eleve el valor de n a la potencia x, regrese el numero elevado. Hacer un programa que pruebe las funciones de un modulo compuesto de un archivo de encabezado (.h) y un archivo fuente (.cpp) que contenga las siguientes funciones: - Convierta de centmetros a pulgadas - Convierta de pulgadas a centmetros - Convierta de metros a yardas - Convierta de yardas a metros - Convierta de kilmetros a millas - Convierta de millas a kilmetros

Argumentos por omisin Si la funcin tiene un prototipo los argumentos por omisin se declaran en el prototipo y no en la definicin. Si la funcin no tiene prototipos se pueden declarar en la definicin. Hay que notar que no todos los argumentos deben de estar definidos por omisin; puede ser uno solo pero este solo puede estar al final de la lista de argumentos. Ejemplo: Formato(int x, int y, int z = 0); Formato(int x, int y = 0, int z = 0); Esto es valido, los ltimos argumentos en la lista son por defecto.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

74

Formato(int x, int y = 0, int z); Formato(int x = 0, int y, int z = 0); Esto es invlido, una vez que se pone un argumento por omisin en la lista todos los dems que le siguen deben ser por omisin. Listado
// omision.cpp // Argumentos por omision de las funciones // en los prototipos de las funciones de C++ #include <iostream> using namespace std; void muestra(int = 1, float = 2.3, long = 4); int main() { muestra(); muestra(5); muestra(6, 7.8); // Los tres parametros por defecto // Provee el primer parmetro // Provee los primeros dos

muestra(9, 10.11, 12L); // Provee los tres parametros return 0; } void muestra(int pr, float seg, long ter) { cout << "\n Primero = " << pr; cout << ", Segundo = " << seg; cout << ", Tercero = " << ter; }

Salida
Primero = 1, Segundo = 2.3, Tercero = 4 Primero = 5, Segundo = 2.3, Tercero = 4 Primero = 6, Segundo = 7.8, Tercero = 4 Primero = 9, Segundo = 10.11, Tercero = 12

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

75

void muestra(int = 1, float = 2.3, long = 4); Se declara el prototipo de la funcin con los argumentos por omisin. En el main() se manda llamar la funcin muestra() con diferente nmero de argumentos para que se utilicen los argumentos por omisin.

2.7 Sobrecarga de subprogramas.


La sobrecarga de subprogramas en C++ significa que se pueden tener varias funciones con el mismo nombre, esto es posible ya que el identificador de una funcin se determina por el nombre de la funcin y sus argumentos. Las funciones deben diferir en la lista de argumentos, ya sea en el nmero de variables que se pasan a la funcin, en el tipo de argumentos que recibe o bien en el orden. Listado // sobrecarga.cpp //Sobrecarga de una funcion #include <iostream> using namespace std; int cuadrado(int); //prototipo de funcion sobrecargada double cuadrado(double);//prototipo de funcion sobrecargada int main() { int ix = 5; double dx = 1.5; cout << "El cuadrado de "<< ix << " es "<< cuadrado(ix) << endl; //el compilador al ver un valor int elige la funcion cout << "El cuadrado de " << dx << " es " << cuadrado(dx) << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

76

return 0; }

//Funcion sobrecargada para valores int int cuadrado(int y ) { return y*y; } //Funcion sobrecargada para valores double double cuadrado(double y) return y*y; } Salida El cuadrado de 5 es 25 El cuadrado de 1.5 es 2.25 {

2.8 Recursividad
Una funcin es recursiva si una sentencia en el cuerpo de una funcin se llama a si Listado // recursiva.cpp // Usa una funcion normal y una recursiva para sacar el factorial #include <iostream> using namespace std; int factorial(int n) { // no recursiva int i, f = 1; for (i = 1; i <= n; i++) f = f * i; return f; } misma.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

77

int factorial_recusiva(int n) { // Funcion recursiva if (n == 0) return 1; else return n * factorial_recusiva(n-1); } int main() { int n; cout << "ingrese un numero "; cin >> n; cout << "El factorial de " << n << " es " << factorial(n) << endl; cout << "El factorial de " << n << " es " << factorial_recusiva(n) << endl; return 0; } Salida en base a la entrada de ejemplo ingrese un numero 5 El factorial de 5 es 120 El factorial de 5 es 120

Funciones inline Las funciones en lnea se declaran anteponiendo la palabra inline al tipo de dato de la funcin, y stas funciones actan como macros; el compilador pone el cdigo que se encuentra dentro de la funcin en la parte donde est el llamado como si fuera escrito ah originalmente, esto hace que el programa sea mas grande pero se evita el tiempo del llamado a la funcin haciendo el programa mas rpido, con la ventaja de tener el cdigo centralizado en una sola parte y con el chequeo de sintaxis de una funcin. Las funciones en lnea que contienen ciclos no son expandidas y generalmente el compilador da una advertencia. Nota:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

78

El compilador puede ignorar una declaracin inline; y tambin dependiendo de las optimizaciones que se usen, el compilador puede hacer funciones en lnea que no se declararon como inline.

Listado // enlinea.cpp // funciones en linea // utiliza una funcin "inline" para intercambiar dos valores #include<iostream> #include <ctime> using namespace std; // Las funciones inline (en linea) se expanden donde se llaman inline void cambia(char &a, char &b) { char c; if (rand()%2) { c = a; a = b; b = c; } } void tabs(int n) { int i; for (i = 0; i < n; i++) cout << "\t"; } int main() { int i; char x, y; x = '#'; y = 'O'; srand( (unsigned)time( NULL ) ); for (i = 0; i < 10; i++) { tabs(i); cout << x << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

79

cambia(x, y); } return 0; }

Salida
# # O O O O O # # #

inline void cambia(char &a, char &b)


La palabra inline indica que la funcin ser expandida donde sea llamada.

for (i = 0; i < 10; i++) { tabs(i); cout << x << endl; cambia(x, y); } Aqu se encuentra la llamada a la funcin cambia y en esta parte se incluye el cdigo de la funcin en lugar del cdigo para llamarla por parte del compilador.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

80

Capitulo 3
Punteros, referencias y arreglos

3.1 Creacin
Un puntero es un a variable que almacena una direccin de memoria. Esta direccin es usualmente la localidad de otra variable en memoria. Si una variable contiene la direccin de otra variable, entonces se dice que la primera variable apunta a la segunda. Los punteros son usados para accesar en forma expedita porciones de memoria.

Pasos a seguir al usar punteros


1. Define el puntero (Usando el *) char *pn; 2. Inicializa el puntero para apuntar a algo (Usando &) pn = &n; 3. Toma a lo que este apuntando el puntero (Usando *), a este proceso se le llama indireccin cout << pn esta apuntando a << *pn; Ejemplo: char c, n, *pn; n = 'X'; pn = &n; c = *pn; ( c = 'X')

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

82

fig1. Simplificacin de variables en memoria

El operador & solo se puede aplicar a variables y a elementos de un arreglo. Son ilegales construcciones como: &(x+1) &3 Listado // apunta.cpp // ejemplo de punteros e indireccion // recomendable analisar la salida al mismo tiempo que el codigo #include <iostream> using namespace std; int main() { int n; int *pn; n = 123; cout << endl << "n = 123;"; cout << endl << "valor de n=" << n << " Direccion de n=" << &n << endl; pn = &n; // pn apunta a n (contiene la direccion de n) cout << endl << "pn = &n;"; cout << endl << "Valor de pn=" << pn << " Valor a donde apunta pn=" << *pn << endl; *pn = 321; // se accesa n indirectamente cout << endl << "*pn = 321;"; cout << endl << "valor de n=" << n

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

83

<< endl; n++; cout << endl << "n++;"; cout << endl << "acceso indirecto al valor de *pn=" << *pn; return 0; }

Salida (los valores de las direcciones son dependientes de la ejecucin)


n = 123; valor de n=123 Direccion de n=0xbfb9aaf8 pn = &n; Valor de pn=0xbfb9aaf8 Valor a donde apunta pn=123 *pn = 321; valor de n=321 n++; acceso indirecto al valor de *pn=322

La salida explica el programa al mostrar los valores, las direcciones de las variables, y como se asigna estas direcciones a la variable de tipo puntero, adems del acceso indirecto que se logra por medio del puntero.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

84

3.2 Operaciones con punteros


Mediante un puntero se puede acceder a diferentes direcciones de memoria siempre y cuando sea del mismo tipo. Se puede realizar comparaciones entre punteros y hacer restas y sumas a punteros y entre punteros. Al incrementar o decrementar un puntero, ste apuntara a la posicin de memoria del elemento siguiente o anterior segn sea el caso en funcin de su tipo base. Ejemplo: char *pn, n =X; pn = &x;

fig2. Simplificacin de memoria, en base a una maquina de 16 bits pn++;

fig3. Simplificacin de memoria, en base a una maquina de 16 bits Listado // operap.cpp // operaciones con punteros #include <iostream> using namespace std; int main() { char a, b, *pc1, *pc2; a = 'A'; b = 'B'; pc1 = &a; cout << "pc1 = &a;" << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

85

cout << " Acceso indirecto variable \"a\" mediante pc1 " << *pc1 << endl; pc1 = &b; cout << "pc1 = &b;" << endl; cout << " Acceso indirecto variable \"b\" mediante pc1 " << *pc1 << endl; pc2 = pc1; cout << "pc2 = pc1;" << endl; cout << " Acceso indirecto variable \"b\" mediante pc2 " << *pc1 << endl; if (pc1 == pc2) cout << "Los dos punteros apuntan a la misma direccion" else cout << "Los dos punteros apuntan a diferentes direcciones" << endl; pc1 = &a; cout << "pc1 = &a;" << endl; if (pc1 == pc2) cout << "Los dos punteros apuntan a la misma direccion" << endl; else cout << "Los dos punteros apuntan a diferentes direcciones" << endl; // Se incrementa el contenido de donde apunta pc1 cout << endl << "Valor de donde apunta pc1 = " << *pc1 << endl << "(Valor de donde apunta pc1) + 1 = " << char(*pc1 + 1) << endl << "(Valor de donde apunta pc1) + 2 = " << char(*pc1 + 2) << endl; return 0; } << endl;

Salida
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 86

pc1 = &a; Acceso indirecto variable "a" mediante pc1 A pc1 = &b; Acceso indirecto variable "b" mediante pc1 B pc2 = pc1; Acceso indirecto variable "b" mediante pc2 B Los dos punteros apuntan a la misma direccion pc1 = &a; Los dos punteros apuntan a diferentes direcciones Valor de donde apunta pc1 = A (Valor de donde apunta pc1) + 1 = B (Valor de donde apunta pc1) + 2 = C

pc1 = &a; Se asigna la direccin de la variable a. char(*pc1 + 1) Incrementa el contenido de donde apunta pc1, el valor de la variable a es A que es 65 en cdigo ASCII, 65 + 1 = 66 y lo despliega como carcter con la conversin a tipo char(). Nota: La aritmtica de punteros se analiza despus de estudiar arreglos, en el siguiente tema.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

87

Puntero nulo Un puntero nulo es un puntero que apunta a NULL, es decir apunta a una direccin cero, se dice que es un puntero 0. El puntero NULL no concide con ninguna direccin de variable o funcin. Muy til en manejo de colas, listas, pilas, etc. Punteros a void Es aquel que apunta a un tipo void. Significa que el puntero no apunta a ningn tipo de valor... y es ms o menos genrico, es decir se puede usar para apuntar a diferentes tipos de memoria. (Ms o menos genrico porque no se permite la asignacin de la direccin de una constante o de punteros a constantes, punteros a miembros de una clase, etc) Ejemplo: void *puntero;

Indireccion simple y mltiple

fig4, Simplificacin de indireccion

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

88

Ejemplo: float **n; Aqu n no es un puntero a un numero en punto flotante, sino un puntero aun puntero float. Listado // indir_multiple.cpp // Ejemplo de indireccion multiple #include <iostream> using namespace std; int main() { int x, *p, **q; x = 10; p = &x; q = &p; cout << endl << "q=" << q << endl << "*q=" << *q << endl << "**q=" << return 0; } Salida (Dependiente de la ejecucin) q=0xbfff1f40 *q=0xbfff1f44 **q=10 **q;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

89

Llamada por punteros En este mtodo, la direccin en memoria del argumento es copiada dentro del argumento de la funcin. La direccin es usada para accesar el valor en memoria de la variable usada en la llamada. Para usar este mtodo se pasa una direccin de memoria como argumento. Los punteros son pasados a la funcin como cualquier otro valor pero declarando los parmetros de tipo apuntador. Listado // cambia.cpp // intercambia dos numeros con una funcion #include <iostream> using namespace std; void cambia(int *x, int *y) { int paso; paso = *x; *x = *y; *y = paso; } int main() { int x = 20, y = 10; cout << "x=" << x << " cambia(&x, &y); cout << "x=" << x << " return 0; } Salida 10 20 y=" << y; y=" << y << endl;

void cambia(int *x, int *y) {

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

90

Las variables dentro de los parntesis indican que se va a recibir direcciones, al igual void indica que la funcin no va a regresar un valor.

cambia(&x, &y);
El smbolo & antes del nombre de la variable indica que se manda la direccin de la variable.

Punteros a funciones Las funciones se encuentran dentro de la memoria de segmento de cdigo, por lo tanto la direccin de inicio de la funcin se puede asignar a un puntero. Teniendo una funcin: int nombre_funcion(int char *); Se declara un puntero a funcin: int (*puntero_a_funcion) (int, char *) Para inicializar el puntero: puntero_a_funcion = nombre_funcion;

3.3 Referencias
Una referencia es la asociacin de un nombre a un objeto determinado; una referencia es como un puntero constante al que se le aplica una indireccin cada vez que se hace referencia a ste. Es como un puntero porque aloja una direccin y como una variable comn porque no se tiene que usar una notacin especfica como en el caso de los punteros cuando se usa la variable. La variable tipo referencia debe inicializarse al momento de declararse. Listado // referencias.cpp // ejemplo de referencias #include <iostream> using namespace std; int main() { int n = 123; int &rn = n; cout << "n=" << n << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

91

cout << "rn=" << rn << endl << endl; rn++; cout << "rn++=" << rn << endl; cout << "n=" << n << endl << endl; n++; cout << "n++=" << n << endl; cout << "rn=" << rn << endl; return 0; }

Salida n=123 rn=123 rn++=124 n=124 n++=125 rn=125

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

92

int &rn = n;
Se declara la variable de referencia rn, con el signo & antes de la variable y se hace referencia a la variable n.

rn++;
Se incrementa indirectamente la variable n por medio de la referencia.

cout << "\n rn

= " << rn;

Se despliega el valor de n por medio de la referencia rn.

Llamada por referencia El argumento de la funcin es inicializado con la direccin en memoria del argumento, la referencia es usada para accesar el valor en memoria de la variable usada en la llamada. Listado // cambia_rf.cpp // Usa una funcion que intercambia los valores de sus argumentos // utilizando paso por Referencia #include <iostream> using namespace std; void cambia(int &a, int &b) { int paso; paso = a; a = b; b = paso; } int main() { int x, y; x = 10; y = 20;

cambia(x, y); cout << endl << "X = " << x; cout << endl << "Y = " << y;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

93

return 0; }

Salida X = 20 Y = 10

void cambia(int &a, int &b) { Se declara la funcin con paso por referencia cambia(x, y); Se llama la funcin. Note que en la llamada no se encuentra diferencia entre la referencia. llamada por valor y la de por

3.4 Arreglos unidimensionales, bidimensionales y multidimensionales


Arreglos unidimensionales Los arreglos son listas en memoria de variables del mismo tipo reunidas bajo un mismo nombre; cada variable de la lista puede ser accesada individualmente mediante un nmero el cual corresponde al orden en que son almacenadas, a este nmero se le llama ndice.
Forma general: tipo nombre_variable[tamao] En C++ todos los arreglos usan el cero como ndice del primer elemento.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

94

Ejemplo: int lista[3];

Declara un arreglo llamado lista con tres elementos desde lista[0] hasta lista[2]. Listado // fecha.cpp // elementos del arreglo accesados fuera de un ciclo #include <iostream> using namespace std; int main() { int fecha[3]; fecha[0] = 1; fecha[1] = 1; // mes // dia

fecha[2] = 2010; // aa cout << "Fecha "; cout << fecha[0] << '/' << fecha[1] << '/' << fecha[2]; return 0; } Salida Fecha 1/1/2010

int fecha[3]; Se declara un arreglo de enteros de tres elementos. fecha[0] = 1; fecha[1] = 1; fecha[2] = 2010; Se le asigna valores al arreglo elemento por elemento.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

95

Ejercicio 1. Modifique el ejemplo anterior (fecha.cpp) para que lea la fecha del teclado.

Listado // ordena_c.cpp // Lee un arreglo de enteros y ordena los elementos de mayor a menor #include <iostream> using namespace std; const int TAM = 3; int main() { int iCalificacion[TAM], iCalifTemp; int i, j; cout << "Ingresa calificaciones" << endl; for (i = 0; i < TAM; i++) { cout << "Calificacion " << i << "? "; cin >> iCalificacion[i]; } // Ordena califcaciones en base a la califiacion de mayor a menor for (i = 0; i < TAM; i++) for (j = 0; j < TAM; j++) { // ordena de mayor a menor if (iCalificacion[i] > iCalificacion[j]) { // intercambia la califcacion iCalifTemp = iCalificacion[i]; iCalificacion[i] = iCalificacion[j]; iCalificacion[j] = iCalifTemp; } } cout << endl << "Calificaciones de mayor a menor: " << endl; for (i = 0; i < TAM; i++) cout << iCalificacion[i] << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

96

return 0; }

Salida en base a la entrada de ejemplo


Ingresa calificaciones Calificacion 0? 100 Calificacion 1? 90 Calificacion 2? 95 Calificaciones de mayor a menor: 100 95 90

const int TAM=3; Declara una constante de tipo entero, es decir un almacenamiento con el nombre TAM el cual no puede ser cambiado durante la ejecucin del programa. for (i = 0; i < TAM; i++) { cout << "Calificacion " << i << "? "; cin >> iCalificacion[i]; } Se llena el arreglo dentro del ciclo for. for (i = 0; i < TAM; i++) for (j = 0; j < TAM; j++) { // ordena de mayor a menor if (iCalificacion[i] > iCalificacion[j]) { // intercambia la califcacion iCalifTemp = iCalificacion[i]; iCalificacion[i] = iCalificacion[j]; iCalificacion[j] = iCalifTemp; } } En estas lneas el arreglo es ordenado en base al valor mayor. El ordenamiento del arreglo se realiza al comparar el primer elemento del arreglo con todos los dems y si se cumple la condicin, el elemento que es comparado con todos se intercambia, el

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

97

segundo con todos y as sucesivamente, en este algoritmo el ciclo interno es el que controla el ordenamiento, en este caso moviendo el mayor hacia el primer elemento del arreglo. Ejemplo 1: Ingresa calificaciones Calificacion 0? 1 Calificacion 1? 4 Calificacion 2? 7 Calificaciones de mayor a menor: 7 4 1 Ejemplo 2: Ingresa calificaciones Calificacion 0? 4 Calificacion 1? 1 Calificacion 2? 7 Calificaciones de mayor a menor: 1 4 7 Primera pasada: 417 147 Segunda pasada: 147 147 Tercera pasada: 147 147 Primera pasada: 147 147 Segunda pasada: 147 417 Tercera pasada: 417 741

Este mtodo de ordenamiento es fcil de implementar, pero definitivamente no es el ms eficiente, se puede observar que se pierden ciclos al repetir las comparaciones y redundar el ordenamiento. Se puede optimizar al pasar el control del ordenamiento al primer ciclo haciendo lo siguiente: for (i = 0; i < TAM; i++) for (j = i+1; j < TAM; j++) { if (iCalificacion[i] < iCalificacion[j]) { iCalifTemp = iCalificacion[i]; iCalificacion[i] = iCalificacion[j]; iCalificacion[j] = iCalifTemp; } }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

98

Note que se asigna a la variable de control del ciclo interno el valor de la variable de control del ciclo externo mas uno, para no repetir la comparacin, tambin se cambia la condicin de mayor que a menor que. Ejercicios 1. Modifique el ejemplo anterior (ordena_c.cpp) para que ordene el arreglo de menor 2. Realice un programa que a) Pida diez nmeros enteros y los almacene en un arreglo b) Busque el nmero menor y el nmero mayor en el arreglo ledo c) Despliegue el nmero menor y el nmero mayor

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

99

Comprobacin de contornos El lenguaje C++ no realiza comprobacin de contornos en los arreglos. Si se sobrepasa el final durante una operacin de asignacin, entonces se asignarn valores a otras variables en memoria o memoria usada por el propio cdigo del programa, lo que puede provocar resultados no deseados, o un error que detiene la ejecucin del programa. Las comprobaciones son responsabilidad del programador. Listado // for_out.cpp // Programa que sobrepasa el limite de indexacion #include <iostream> using namespace std; int main() { int lista[10], i; for (i = 0; i < 100; i++) { lista[i] = i; cout << lista[i] << ' '; } return 0; } Salida (depende de la ejecucin, puede marcar errores de memoria y no haber salida) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

Nota: Este programa compilar bien. Y sirve de ejemplo para la comprobacin de los lmites del arreglo.

Arreglos bidimensionales y multidimensionales Los arreglos multidimensionales son arreglos con ms de un ndice, por ejemplo los bidimensionales son arreglos con dos subndices que son usados para

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

100

representar tablas de valores, con informacin organizada en reglones y columnas. Para accesar un elemento particular de la tabla hay que identificar el rengln del elemento seguido por la columna. Forma general:
tipo nombre[longitud_1][longitud_2] Ejemplo: int matriz[3][2];

Declara un arreglo 3 x 2 llamado matriz con seis elementos desde matriz[0][0] hasta matriz[2][1]. Listado // sumamat.cpp // Suma dos matrices dejando el resultado en una tercera #include <iostream> using namespace std; const int LON = 2; int main(){ int i, j, a[LON][LON], b[LON][LON], c[LON][LON]; cout << "Ingresa la matriz A " << endl; for (i=0; i < LON; i++) for (j=0; j < LON; j++) { cout << "A[" << i << "][" << j << " ] = ? "; cin >> a[i][j]; } cout << endl << "Ingresa la matriz B " << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

101

for (i=0; i < LON; i++) for (j=0; j < LON; j++) { cout << "B[" << i << "][" << j << " ] = ? "; cin >> b[i][j]; } // Suma las matrices y deja el resultado en una tercera matriz for (i=0; i < LON; i++) for (j=0; j < LON; j++) c[i][j] = a[i][j] + b[i][j]; cout << endl << "El resultado de la suma de A + B es:" << endl; for (i=0; i < LON; i++) { for (j=0; j < LON; j++) cout << c[i][j] << "\t"; cout << endl; } return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

102

Salida en base a la entrada de ejemplo


Ingresa la matriz A A[0][0 ] = ? 1 A[0][1 ] = ? 1 A[1][0 ] = ? 1 A[1][1 ] = ? 1 Ingresa la matriz B B[0][0 ] = ? 2 B[0][1 ] = ? 2 B[1][0 ] = ? 2 B[1][1 ] = ? 2 El resultado de la suma de A + B es: 3 3 3 3

int i, j, a[LON][LON], b[LON][LON], c[LON][LON]; Se declaran las variables a ser usadas, i y j para usarlas como subndices y tres arreglos de dos dimensiones. for (i=0; i < LON; i++) for (j=0; j < LON; j++) { cout << "A[" << i << "][" << j << " ] = ? "; cin >> a[i][j]; } Se usan dos for, el primero para accesar los renglones y el segundo que est dentro del cuerpo del primer for para accesar las columnas. 1 for (i=0; i < LON; i++) 2 3 for (j=0; j < LON; j++) c[i][j] = a[i][j] + b[i][j];

Se suman los dos arreglos dejando el resultado en el tercer arreglo. Ejercicio

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

103

Realice un programa que pida un arreglo de 3x3 y sume la diagonal principal, despliegue la suma.

Arreglos de ms de dos dimensiones Un arreglo de enteros de tres dimensiones de 2 x 2 x 2 se declarara de la siguiente manera: int cubo[2][2][2]; Para acceder el primer elemento seria: cubo[0][0][0] = 0; //asigna cero al primer elemento del arreglo tridimensional Para un arreglo de enteros de cuatro dimensiones de 2 x 2 x 2x2 se declarara de la siguiente manera: int cuatridimensional[2][2][2][2]; Para acceder el primer elemento seria: cuatridimensional [0][0][0][0] = 0; //asigna cero al primer elemento del arreglo Este tipo de arreglos son raramente usados ya que aumenta la complejidad del programa y generalmente la solucin del problema se pude replantear para evitar complejidades innecesarias, en caso de que sea inevitable siempre se puede usar este tipo de arreglos.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

104

Arreglos y punteros
Cuando se declara un arreglo el compilador debe asignar una direccin base y la cantidad de almacenamiento suficiente para alojar a todos los elementos del arreglo. Los punteros y arreglos se utilizan casi de la misma manera para acceder a la memoria. Nota El nombre de un arreglo es una constante que contiene la direccin del inicio del arreglo tambin llamado puntero fijo y un puntero es una variable cuyos valores son direcciones.

Listado // a_apunta.cpp // Relacion entre arreglos y punteros #include <iostream> using namespace std; int main(){ char cstr1[] = "ARREGLO"; char cstr2[] = "PUNTERO"; char *pc; cout << "cstr1: " << cstr1 << endl; cout << "cstr2: " << cstr2 << endl; pc = cstr1; cout << "\npc: " << pc; pc = cstr2; cout << "\npc: " << pc; return 0; }

Salida en base a la entrada de ejemplo


cstr1: ARREGLO cstr2: PUNTERO

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

105

pc: ARREGLO pc: PUNTERO

char cstr1[] = "ARREGLO"; char cstr2[] = "PUNTERO"; Se declaran dos arreglos de caracteres y se inicializan,. char *pc; Se declara la variable de tipo puntero. cout << "cstr1: " << cstr1 << endl; cout << "cstr2: " << cstr2 << endl; Se despliega el contenido de cstr1 y cstr2, (lneas 11 y 12). pc = cstr1; Se asigna la direccin de la cadena de caracteres y en la siguiente lnea se despliega el contenido de cstr1 por medio del puntero pc.

3.5 Cadenas de caracteres


Una cadena de caracteres consiste en un arreglo de caracteres terminado en un nulo. Un nulo se especifica como '\0'. Si se quiere definir una cadena de 5 elementos se debe definir de 6 para soportar el carcter nulo. Ejemplo: char str[6]; Una constante de cadena es una lista de caracteres que se encierran entre comillas. Ejemplo: "HOLA" Al declarar una constante de cadena el compilador de C++ agregara automticamente el carcter nulo al final. La cadena "HOLA" se vera en memoria as:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

106

Listado // cadena.cpp // Cadenas de caracteres #include <iostream> using namespace std; int main() { char s[16]; char s2[] = {'h', 'o', 'l', 'a', '\0'}; char s3[] = "HOLA A TODOS"; cout << endl << "Ingresa una cadena de caracteres "; // El "cin" por si solo, deja de leer cuando encuentra // un espacio cin.getline(s, 15); // para incluir espacios en la cadena cout << "s=" << s << endl << "s2=" << s2 << endl << "s3=" << s3 << endl; s3[5] = '\0'; cout << "s3=" << s3 << endl; return 0; }

Salida en base a la entrada de ejemplo


Ingresa una cadena de caracteres Issac Asimov s=Issac Asimov s2=hola s3=HOLA A TODOS s3=HOLA

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

107

char s[16]; Declara un arreglo de caracteres. char s2[] = {'h', 'o', 'l', 'a', '\0'}; Se declara un arreglo de caracteres y se inicializa, este tipo de inicializacin en arreglos solo es permitido al momento de declarar el arreglo. La asignacin del elemento '\0' al final del arreglo es para tratar el arreglo como una cadena de caracteres. Hay que notar que no se indica cuantos elementos tiene el arreglo; como se est inicializando se deja la cantidad fuera de la declaracin para que el compilador incluya la cantidad en s2[]. char s3[] = "HOLA A TODOS"; Se declara un arreglo de caracteres y se inicializa con una cadena de caracteres. Al hacer la inicializacin de esta forma, el compilador incluye adems de la cantidad de elementos en s3[] el carcter \0 al final, este tipo de inicializacin en arreglos solo es permitido al momento de declarar el arreglo. La cadena s3 se vera en memoria as:

s3[5] = '\0'; Se asigna el carcter nulo en el quinto elemento, por lo tanto: La cadena s3 se vera en memoria as:

cout << s3 << endl; Despliega la cadena s3, siendo la salida HOLA , porque el cout se detiene al encontrar el primer carcter '\0' que es el que indica el fin de cadena. Listado // mayusculas.cpp // Convierte una cadena de caracteres a mayusculas #include <iostream> using namespace std;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

108

char mensaje[80]; void mayusculas(void) { int i; for (i = 0; mensaje[i] != '\0'; i++) mensaje[i] = toupper(mensaje[i]); } main() { cout << "\Ingresa un mensaje "; cin.getline(mensaje, 79); mayusculas(); cout << "\nEl mensaje en mayusculas es " << mensaje; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

109

Salida
Ingresa un mensaje issac asimov El mensaje en mayusculas es ISSAC ASIMOV

char mensaje[80]; Se declara una cadena de caracteres global para las funciones que estn abajo de sta. void mayusculas(void) { El primer void significa que la funcin no regresa nada, acta como un procedimiento. mayusculas es el nombre de la funcin y void dentro de los parntesis significa que la funcin no recibe parmetros. En el cuerpo de la funcin se convierte cada elemento de la cadena de caracteres a maysculas. mayusculas(); Manda llamar la funcin.
Ejercicios 1. Realice un programa que ingrese y despliegue una cadena de caracteres elemento por elemento. 2. Hacer un programa que lea y almacene una cadena caracteres con un mximo de 80 caracteres y despliegue la cadena en maysculas, investigue el uso de la funcin toupper() (#include <ctype>) 3. Hacer un programa que lea y almacene una cadena caracteres con un mximo de 80 caracteres y despliegue la cadena en orden inverso, recuerde que el carcter nulo \0 indica el fin del texto.

Apuntadores a caracteres

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

110

Si se declara mensaje como: char *mensaje; La sentencia: mensaje = "esta es una cadena" Asigna a mensaje un apuntador a los caracteres. No es la copia de una cadena. Listado // strlen_punteros.cpp // Ejemplo de como puede estar implementada la funcion de la // biblioteca estandard strlen (implementada usando apuntadores) int strlen(char *s) { char *p = s; while (*p != '\0') p++; return p-s; } Ejercicios 1. Analice como es que la funcin cuenta el nmero de caracteres contenidos en la cadena 2. Implemente la funcin main para probar la funcin

Listado // copia_cadena.cpp // Copia origen a destino usando apuntadores #include <iostream> using namespace std; void copia_cadena(char *destino, char *origen) { do { *destino = *origen; destino++; origen++; } while(*origen != '\0'); *destino = *origen; // copia el caracter '\0' }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

111

int main(){ char str1[80], str2[80]; cout << "Ingresa un string "; cin.getline(str1, 79); copia_cadena(str2, str1); cout << str2 << endl; return 0; } Salida en base a la entrada de ejemplo Ingresa un string Bjarne Stroustrup Bjarne Stroustrup

Ejercicio 1. Escriba una funcin str_busca(str, c) que reciba un apuntador a una cadena de caracteres str, y un carcter c. Busque el carcter en la cadena y regrese la posicin en que se encuentra el carcter en la cadena o un -1 si no se encuentra utilizando apuntadores. 2. 3. Realice una funcin concatena(str1, str2) que agregue la cadena de caracteres str2 al final de la cadena str1. Realice una funcin reversa(str) que reciba un apuntador a una cadena de caracteres e invierta la cadena. Utilizando apuntadores.

Aritmtica de punteros Ejemplo: Teniendo: int n[3] = {1, 2, 3}, *p; Las siguientes sentencias son equivalentes; ambas asignan la direccin de inicio del arreglo al puntero p. p = n; p = &n[0];

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

112

fig5. Simplificacin de memoria, maquina de 16 bits Las siguientes sentencias son equivalentes; ambas asignan la direccin de memoria del segundo elemento al puntero p. p = n + 1; p = &n[1];

fig6. Simplificacin de memoria, maquina de 16 bits Las siguientes sentencias son equivalentes para accesar el contenido de un elemento: n[i]; *(p+i) Las siguientes sentencias son equivalentes para accesar la direccin de un elemento: &n[i]; n+i; Un apuntador es una variable, por lo que son correctas las siguientes operaciones: p = n; p++; El nombre de un arreglo es una constante; as que son ilegales construcciones como: n = p; n++; p = &n; n = n + 2; Listado // aritmetica_puntero.cpp

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

113

// Aritmetica de punteros #include <iostream> using namespace std; int main() { char *p, s[] = "ABCDEFG"; p = s; // despliega la cadena a traves del puntero cout << endl << p << endl << p[0] << endl << p+2; return 0; } // toda la cadena // un elemento, el primero // a partir del tercer elemento

<< endl << *(p+1) // un elemento, el segundo

Salida
ABCDEFG A B CDEFG

char *p, s[] = "ABCDEFG"; Se declara un carcter, una cadena de caracteres y un puntero a caracteres, que se utiliza para accesar el contenido de la cadena y del carcter en el resto del programa. p = s; Se asigna la direccin de s al puntero p. cout << endl << p[0] Despliega el primer elemento de la cadena s indirectamente, esto es equivalente a decir *p, el contenido de donde apunta p. << endl << *(p+1) Despliega, el contenido del segundo elemento de s, esto es equivalente a p[1], aqu se realiza primero la operacin de lo que esta entre parntesis, se incrementa la direccin del puntero y despus accesa el contenido de la direccin que contiene p despus de la suma *(p+1).

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

114

<< endl << p+1; Incrementa el contenido de la variable (en una direccin note que esto solo es temporalmente) y despliega la cadena a partir de la direccin del elemento 2, como se muestra.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

115

3.6 Asignacin dinmica de memoria


Manejar la memoria dinmicamente es til cuando no se sabe la cantidad o el tipo de objeto hasta que el programa est en ejecucin, o cuando se quiere que los objetos no estn sujetos a las reglas normales de alcance definidas por el lenguaje. Normalmente se definen y se usan los objetos en tiempo de compilacin, el manejo dinmico de la memoria libera de la limitante de saber todo al tiempo de compilacin, permitiendo crear y destruir objetos en tiempo de ejecucin. new Aloja memoria dinmicamente, regresa un apuntador a la memoria alojada. Si falla resulta una excepcin bad_alloc. Ejemplo: int *n; n = new int; Aloja memoria suficiente para almacenar un entero. delete Desaloja un bloque de memoria dinmica que ha sido previamente alojado por el operador new. El desalojo de memoria la libera para su reutilizacin. Ejemplo: int *n; n = new int; delete n; Desaloja la memoria que fue separada por new y asigna un nulo al puntero. Listado // new_del.cpp // ejemplo de manejo dinmico de memoria // Operadores new y delete con un arreglo #include <iostream> using namespace std; int main() { int *ca;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

116

ca = new int[3]; // Toma memoria para el arreglo ca[0] = 8; ca[1] = 21; ca[2] = 2020; cout << "Fecha "; cout << ca[0] << '/' << ca[1] << '/' << ca[2]; delete []ca; // Regresa la memoria al almacenamiento libre return 0; }

Salida
Fecha 8/21/2020

int *ca; Se declara un puntero a enteros. ca = new int[3]; new, separa memoria necesaria para almacenar 3 enteros y le asigna la direccin de inicio del bloque de memoria separado. En el programa se trata el bloque como un arreglo normal (los arreglos y el manejo de punteros esta ntimamente ligado) y se le asigna enteros a cada elemento. delete []ca; Se libera el bloque de memoria separado anteriormente con el operador new. Listado // asientos.cpp // anejo dinmico de memoria utilizando un arreglo de strings, // el programa administra un lugar con asientos numerados. #include <iostream> #include <string>

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

117

using namespace std; int main() { int total_asientos, numero, i; string *asiento; cout << "\nCantidad de asientos con que cuenta el local? "; cin >> total_asientos; // Toma la longitud del arreglo

asiento = new string[total_asientos]; // Aloja el arreglo do { for (i=0; i < total_asientos; i++) cout << endl << "Asiento " << i << ": " << asiento[i]; cout << endl << "Numero de Asiento? (-1 termina)"; cin >> numero; if (numero < 0) break; cout << "Nombre "; cin >> asiento[numero]; } while(1); delete []asiento; return 0; }

Salida en base a la entrada de ejemplo


Cantidad de asientos con que cuenta el local? 3 Asiento 0: Asiento 1: Asiento 2:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

118

Numero de Asiento? (-1 termina)1 Nombre Batman Asiento 0: Asiento 1: Batman Asiento 2: Numero de Asiento? (-1 termina)0 Nombre Superman Asiento 0: Superman Asiento 1: Batman Asiento 2: Numero de Asiento? (-1 termina)

string *asiento; Se declara un puntero a string asiento = new string[total_asientos]; Se crea un bloque de memoria suficiente para almacenar el nmero asignado a la variable total_asientos. El resto del programa muestra los elementos y se accesa el elemento seleccionado por el usuario, en caso de que el numero sea -1 se cumple la condicin del if y se ejecuta la instruccin break que termina el ciclo do .. while delete []asiento; delete, regresa el bloque de memoria al almacenamiento libre. Ejercicio

Modifique el programa ordena_c.cpp para que pida la cantidad de calificaciones al momento de ejecucin, es decir cree el arreglo dinmicamente

Punteros a estructuras y manejo de memoria dinmica

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

119

El uso de punteros es para generar llamadas por referencia al llamar una funcin, para crear listas encadenadas as como estructuras dinmicas de datos. Cuando un puntero a estructura es pasado a una funcin, solo la direccin de la estructura es puesta en el stack de datos. Esto permite unas llamadas muy rpidas a las funciones. Ejemplo: struct bal { float balance; char nombre[40]; } persona; Declarando un apuntador a estructura. struct bal *p; Esto pone la direccin de la estructura persona en el apuntador p: p = &persona; Para accesar los elementos de la estructura usando un apuntador a esa estructura, usamos: (*p).balance; Los parntesis son necesarios alrededor del apuntador porque el operador punto (.) tiene mayor prioridad mayor que el operador *. El segundo mtodo de acceso es utilizando el operador ->; lo cual nos facilita la programacin. Ejemplo: p->balance;

Para usar asignar memoria dinmica usamos el operador new.


Ejemplo:

p = new bal; Listado


// newstruct.cpp // ejemplo del manejo de memoria dinamica con estructuras. // Los operadores new y delete #include <iostream> using namespace std;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

120

struct Fecha { int mes; int dia; int ayo; }; int main() { Fecha *fecha = new Fecha; fecha->mes = 3; fecha->dia = 30; fecha->ayo = 1968; cout << "\nFecha: " << fecha->mes << '/' << fecha->dia << '/' << fecha->ayo; delete fecha; return 0; } // Regresa la memoria al almacenamiento libre // Toma memoria para una fecha

Salida
Fecha: 3/30/1968

Fecha *fecha = new Fecha; Se declara el puntero de tipo estructura Fecha, y se inicializa con la direccin de inicio del bloque de memoria alojado con el operador new. Operador -> fecha->mes = 3; Es equivalente a: (*fecha).mes
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 121

los parntesis son necesarios ya que el punto (.) tiene mayor procedencia que el asterisco (*) y sin ellos la expresin: *fecha.mes

Significa: (*fecha.mes) Lo cual es ilegal porque mes no es un puntero. Nota: El operado -> se implemento ya que los punteros a estructuras son bastante comunes.

Arreglo de punteros y manejo de memoria dinmica Los apuntadores son variables, as que los podemos almacenar en un arreglo. Declaracin: int *x[10]; Asignacin: x[2] = &v; Encontrar el valor de v. *x[2] Diferencias de arreglos bidimensionales y arreglos de punteros Ejemplo sin punteros: char cap[3][32] = { "introduccion", "tipos, operadores y expresiones", "control de flujo" // No se pone coma };

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

122

introduccion\0 tipos, operadores y expresiones\0 control de flujo\0 Se separan 96 bytes de almacenamiento, siempre, sin importar si se usan o no. Ejemplo con punteros: char *cap[3] = { "introduccion", "tipos, operadores y expresiones", "control de flujo" }; 2000 2000 2002 3000 3001 3002 3000 3001 3002 introduccion\0 tipos, operadores y expresiones\0 control de flujo\0

Se separa solo 63 bytes de almacenamiento + 6 bytes para el almacenamiento de los punteros, es decir solo el espacio estrictamente requerido. Listado // nombres.cpp // Manejo de memoria dinamica, arreglo de punteros #include <iostream> using namespace std; const int LIMITE=5; int main() { char str[80], *nombre[LIMITE]; int i; cout << "Ingresa una lista de nombres" << endl; for (i=0; i < LIMITE; i++) { cout << i << ".-Nombre ? "; cin.getline(str, 79); // Asigna memoria al elemento i del arreglo nombre nombre[i] = new char[strlen(str)+1];

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

123

strcpy(nombre[i], str); // Copia str a nombre } cout << endl << "Lista de nombres:" << endl; for (i=0; i < LIMITE; i++) cout << i << ".- " << nombre[i] << endl; // desaloja la memoria for (i=0; i < LIMITE; i++) delete nombre[i]; return 0; } Salida en base a la entrada de ejemplo Ingresa una lista de nombres 0.-Nombre ? Stroustrup 1.-Nombre ? Abrash 2.-Nombre ? Lamothe 3.-Nombre ? Schildt 4.-Nombre ? Kernighan Lista de nombres: 0.- Stroustrup 1.- Abrash 2.- Lamothe 3.- Schildt 4.- Kernighan

Ejemplo de Asignacin de memoria dinmica con punteros a punteros Listado // punteros_punteros.cpp // manejo de memoria dinamica, punteros a punteros // Modificacion del programa nombres.cpp #include <iostream>

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

124

using namespace std; int main() { char str[80], **nombre; int i, n; cout << endl << "Cantidad de elementos en la lista ? "; cin >> n; // Desecha el ultimo caracter del buffer de entrada // en este caso el caracter nueva linea: '\n' cin.ignore(); nombre = new char *[n]; cout << endl << "Ingresa una lista de nombres"; for (i=0; i < n; i++) { cout << endl << i << ".-Nombre? "; cin.getline(str, 79); // Asigna memoria a nombre nombre[i] = new char[strlen(str)+1]; // Copia str a nombre strcpy(nombre[i], str); } cout << endl << "lista de nombres"; for (i=0; i < n; i++) cout << endl << i << ".-Nombre? " << nombre[i]; // desaloja la memoria de cada elemento for (i=0; i < n; i++) delete nombre[i]; // Desaloja el total de elementos delete nombre; return 0;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

125

} Salida en base a la entrada de ejemplo Cantidad de elementos en la lista ? 3 Ingresa una lista de nombres 0.-Nombre? Bill Watterson 1.-Nombre? Charles M. Schulz 2.-Nombre? Jim Davis lista de nombres 0.-Nombre? Bill Watterson 1.-Nombre? Charles M. Schulz 2.-Nombre? Jim Davis

Argumentos para main Algunas veces es necesario pasar informacin al programa cuando antes de ejecutarse; esta informacin se pasa a la funcin main va la lnea de argumentos. Argumentos en la lnea de comandos Es la informacin que sigue incluyendo el nombre del programa en la lnea de comandos del sistema operativo separada por espacios. Cuando se invoca a main al comienzo de la ejecucin se llama con dos argumentos llamados por costumbre: argc y argv. argc Contiene el nmero de argumentos que estn presentes en la lnea de comandos cuando se invoco el programa.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

126

argv Variable tipo puntero que contiene la direccin al inicio de un arreglo de cadenas de caracteres. Este arreglo contienen los argumentos donde cada cadena contiene un argumento. Ejemplo: 1.- Hacer ejecutable el programa llamado arg.exe por ejemplo. 2.- Ejecutarlo: arg buenos das Nota: Es un arreglo de apuntadores. argc siempre ser 1 porque el primer argumento es el nombre del programa (algunos sistemas operativos incluyen el path).

Listado // args.cpp // argumentos en la linea de comandos #include <iostream> using namespace std; int main(int argc, char *argv[]) { int i; cout << "Numero de Argumentos " << argc; for (i = 0; i < argc; i++) cout << endl << i << " - " << argv[i]; return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

127

Salida Numero de Argumentos 4 0 - args 1 - uno 2-2 3 - tres

3.7 Uso de clases predefinidas para arreglos


Clase vector til para trabajar con cierta cantidad de datos desconocidos y arreglos, pues permite manejar dinmicamente objetos en dichos arreglos, pudiendo crearlos de clases y variables expandiendo o contrayendo el arreglo. Se encuentra definida en el archivo de encabezado vector Listado // vector.cpp // ejemplo de la clase vector #include <vector> #include <iostream> using namespace std; int main() { //Declara un vector simple vector<int> enteros; int i, num; cout << "Ingresa un numero: "; cin >> num; // agrega un elemento al final del vector enteros.push_back(num); // accede a una posicion del vector y se muestra su longuitud cout << endl << "En la posicion 0 esta: " << enteros[0] << endl << "Longitud del vector : " << enteros.size() << endl << "Capacidad del vector : " << enteros.capacity()

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

128

<< endl << "Longitud maxima del vector: " << enteros.max_size(); // vacia el vector enteros.clear(); // agrega 10 elementos al vector for (i=1; i <=10; i++) enteros.push_back(i); for (i=0; i < 10; i++) cout << endl << enteros[i]; cout << endl << "Ahora hay en el vector: " << enteros.size() << " elementos\n"; //Elimina el ultimo elemento del vector enteros.pop_back(); cout << endl << "Hay en el vector: " << enteros.size() << " elementos\n"; return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

129

Salida Ingresa un numero: 55 En la posicion 0 esta: 55 Longitud del vector : 1 Capacidad del vector : 1 Longitud maxima del vector: 1073741823 1 2 3 4 5 6 7 8 9 10 Ahora hay en el vector: 10 elementos Hay en el vector: 9 elementos

Ejercicio 1. 2. Modifique el ejemplo de la pagina 89 (fecha.cpp) para que use la clase vector en vez de un arreglo. Modifique el ejemplo de la pagina 90 (ordena_c.cpp) para que use la clase vector en vez de un arreglo.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

130

Capitulo 4
Clases y objetos

4.1 Definicin de una clase


Una clase es un mtodo lgico de organizar datos y funciones en una misma estructura. La clase es un patrn a seguir al crear objetos. Al definir una clase se define un tipo de dato definido por el usuario, y este tipo sirve para crear instancias de este tipo de dato, a estas instancias se le llama objetos. La definicin de clase es el proceso de definir cuales sern sus propiedades y mtodos; proceso que crea un nuevo tipo de dato.

4.2 Declaracin de clases


La declaracin de clase es la asignacin de un nombre; una sentencia que establece la conexin entre el identificador y el objeto que representa (en este caso una clase). La declaracin asocia el nombre con un tipo de dato, lo que supone definir como se usa, que operaciones son permitidas y que sentido tienen estas operaciones. Ejemplo: class mi_clase; Con frecuencia la declaracin y definicin de una clase ocurren simultneamente en la misma sentencia, igual que con las variables normales, Forma general: class nombre_de_la_clase { etiqueta_de_nivel_de_permiso_1: miembros1;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

132

etiqueta_de_nivel_de_permiso_2: miembros2; ... } nombre_del_objeto;

4.3 Miembros de una clase


Todo lo que esta definido dentro de la clase se dice que es miembro de sta, como variables, arreglos, funciones etc. Las etiqueta_de_nivel_de_permiso se refieren al control de acceso a miembros del objeto. Por defecto los miembros de una clase son privados.

4.4 Ambito referente a una clase


Una clase acta como cualquier otro tipo de dato con respecto al mbito. Todos los miembros de una clase se dice que estn en el mbito de esa clase; cualquier miembro de una clase puede referenciar a cualquier otro miembro de la misma clase. Las funciones miembro de una clase tienen acceso no restringido a los miembros dato de esa clase. El acceso a los miembros dato y funciones de una clase fuera del mbito de la clase est controlado por el programador. La idea es encapsular la estructura de datos y funcionalidad de una clase, de modo que el acceso a la estructura de datos de la clase desde fuera de las funciones miembro de la clase, sea limitada o innecesaria. El nombre de la clase tiene que ser nico dentro de su mbito.

4.5 Especificadores de acceso


private Los miembros que le siguen a esta palabra reservada solo pueden ser accesados por las funciones miembro declaradas dentro de la misma clase. protected Los miembros que le siguen a esta palabra reservada solo pueden ser accesados por las funciones miembro dentro de la misma clase, y por las funciones miembro de las clases que son derivadas de esta clase.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

133

public Los miembros que le siguen a esta palabra reservada pueden ser accesados en cualquier lugar dentro del alcance de la clase. La funcionalidad que brinda el control de acceso protected es usada principalmente cuando se prev que la clase creada va a ser heredada; este tipo de acceso se cubre en el capitulo de herencia.

La funciones estn implementadas dentro de la definicin de la clase, si cumplen con las especificaciones de una funcin inline el compilador las implementa como tales (ver capitulo de subprogramas).

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

134

4.6 Creacin de objetos


Un objeto es una instancia de una clase, la clase es el tipo de dato y el objeto es la variable. Cuando un objeto de la clase es creado, este tendr su propia copia de las variables miembros que contiene la clase. En el siguiente ejemplo se crea una clase para derivar un objeto para representar un emoticon. Los emoticones son una secuencia de caracteres comnmente utilizados en la transmisin de texto mediante correo electrnico, estas secuencias representan una abreviacin de palabras y/o emociones, como por ejemplo :) significa sonrer; :-D rer a carcajadas, etc. Listado // emoticon.cpp #include <iostream> #include <string> using namespace std; class CEmoticon { private: string m_sIcon; public: void Muestra(void){ cout << "\n" << m_sIcon; } void Apariencia(string a_sIcon){ m_sIcon = a_sIcon; } }; int main(){ CEmoticon objeto_icon1; CEmoticon objeto_icon2; objeto_icon1.Apariencia(":O"); objeto_icon2.Apariencia(":]"); objeto_icon1.Muestra(); objeto_icon2.Muestra(); // Declara un objeto de tipo CEmoticon

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

135

cout << endl; objeto_icon1.Apariencia(":)"); objeto_icon1.Muestra(); objeto_icon2.Muestra(); return 0; }

Salida
:O :] :) :]

class CEmoticon {
Se declara la clase CEmoticon usando la palabra reservada class seguida del nombre de la clase.

private: string m_sIcon;


La palabra private especfica que todos los miembros que le siguen hasta que se encuentre con otro especificador o el fin de la clase, solo podrn ser accesados por otros miembros de esta clase, en este caso m_sIcon que es de tipo string.

public: void Muestra(void){ cout << "\n" << m_sIcon; } void Apariencia(string a_sIcon){ m_sIcon = a_sIcon; }
Se declaran los miembros que pueden ser accesados en cualquier parte donde se este usando una instancia de esta clase (objeto).

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

136

La funcin miembro Muestra() es usada para desplegar el contenido de la variable privada m_sIcon y la funcin Apariencia() para cambiar el valor de esta variable. Nota: Las funciones miembro solo pueden ser llamadas en asociacin de un objeto, a diferencia de las funciones definidas fuera de una clase. Las funciones en el ejemplo anterior seran innecesarias si se declarara la variable m_sIcon como publica pero esto ira en contra de la ocultacin de la informacin que es uno de los principios fundamentales de la programacin orientada a objetos. Al definir la clase utilizando miembros privados y pblicos, se puede decir que un objeto tiene un estado interno (miembros privados) y operaciones externas (miembros pblicos).

objeto_icon1.Apariencia(":O"); objeto_icon2.Apariencia(":]");
Cada objeto llama la funcin Apariencia() para cambiar sus respectivas variables m_sIcon.

objeto_icon1.Muestra(); objeto_icon2.Muestra();
Los objetos despliegan el valor de la variable privada m_sIcon mediante sus funciones miembro Muestra().

objeto_icon1.Apariencia(":)"); objeto_icon1.Muestra(); objeto_icon2.Muestra();


Se llama otra vez la funcin Apariencia() asociada al objeto_icono1 y en las se vuelven a desplegar el contenido de las variables de cada objeto.

Ejercicio Cree una clase Persona que contenga el nombre, direccin, telfono y una funcin para actualizar y otra para desplegar los datos.

4.7 Puntero this


(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 137

Cada vez que se crea una instancia de una clase, el objeto ocupa espacio en memoria y this es la palabra reservada con el valor de la direccin en memoria del objeto que est siendo ejecutado. En un objeto, this es un puntero a si mismo, ste es utilizado implcitamente para referenciar todos los miembros del objeto; tambin puede ser utilizado en forma explicita. El siguiente ejemplo es una modificacin a la clase CFecha e incluye una funcin miembro que recibe una referencia a un objeto del mismo tipo y comprueba si los datos que contienen los objetos son iguales o diferentes, adems comprueba s trata de si mismo.

Listado
// cfechacompara.h #pragma once class CFecha { private: int mm, dd, aa; public: CFecha(int a_dd, int a_mm, int a_aa) { mm = a_mm; dd = a_dd; aa = a_aa; } void Fecha(); void Compara(CFecha &fecha); };

void Compara(CFecha &fecha);


Esta funcin recibe una referencia a la clase CFecha (a s misma). Listado // cfechacompara.cpp #include "cfechacompara.h" #include <iostream> using namespace std;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

138

void CFecha::Fecha() { cout << dd << '/' << } void CFecha::Compara(CFecha &fecha) { if (&fecha == this) { cout << "Fechas iguales, mismo objeto"; return; } // if (fecha.mm == this.mm // && fecha.dd == this.dd & fecha.aa == this.aa) if (fecha.mm == mm && fecha.dd == dd & fecha.aa == aa) cout << "Fechas iguales"; else cout << "Fechas diferentes"; } if (&fecha == this) { cout << "Fechas iguales, mismo objeto"; return; } Se compara la direccin en memoria de la referencia al objeto recibido con la direccin actual del objeto que recibi la referencia, usando el this. mm << '/'<< aa;

//if (fecha.mm == this.mm // && fecha.dd == this.dd & fecha.aa == this.aa)


Las lneas que aparecen como comentario son idntica en funcionalidad a las siguientes lneas:

if (fecha.mm == mm && fecha.dd == dd & fecha.aa == aa) cout << "Fechas iguales"; else cout << "Fechas diferentes";
Listado // testcfechacompara.cpp #include <iostream> #include "cfechacompara.h"

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

139

using namespace std; int main() { CFecha f1(10, 1, 05); CFecha f2(22, 1, 05); f1.Fecha(); cout << "\t\t"; f1.Compara(f1); cout << endl; f2.Fecha(); cout << "\t\t"; f2.Compara(f1); return 0; }

Salida
10/1/5 22/1/5 Fechas iguales, mismo objeto Fechas diferentes

CFecha f1(10, 1, 05); CFecha f2(22, 1, 05); Se declaran dos objetos de tipo CFecha y se inicializan mediante su constructor. f1.Compara(f1); El objeto f1 manda llamar la funcin Compara() y le manda la direccin de s mismo. f2.Compara(f1); El objeto f2 manda llamar la funcin Compara() y le manda la direccin del objeto f1. Ejercicios

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

140

3.

Agregue funciones miembro a la clase CFecha en cfecha.h y cfecha.cpp para que actualice el ao, el mes y el da independientemente, as como funciones para que regrese solo el ao, mes y da respectivamente.

4. Hacer un programa con una clase hora que implemente una funcionalidad parecida a la de la clase de fecha.

4.8 Constructores y destructores


Constructores Los constructores son utilizados para inicializar variables miembro porque estas no se pueden inicializar en el momento en que son declaradas. Un constructor es una funcin miembro con el mismo nombre que la clase y no debe regresar un valor; solo es usada para inicializar los datos del objeto. Las funciones constructor son llamadas automticamente cuando se crea un objeto (Una variable del tipo de la clase) sin necesidad de hacer referencias a stas. Por ejemplo si el objeto tiene variables que se deben inicializar a cero o separar memoria dinmicamente, estas operaciones se incluyen dentro del constructor. El siguiente programa es una modificacin del ejemplo anterior y muestra el uso de un constructor y presenta como implementar las funciones miembro fuera de la interfase de la clase. Listado // emoticon2.cpp #include <iostream> #include <string> using namespace std; class CEmoticon { private: string m_sIcon; public: CEmoticon() { Apariencia(":|"); } void Muestra(void){ cout << endl << m_sIcon; } void Apariencia(string a_sIcon); }; void CEmoticon::Apariencia(string a_sIcon) { m_sIcon = a_sIcon; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

141

int main(){ CEmoticon objeto_icon1; CEmoticon objeto_icon2; objeto_icon1.Muestra(); objeto_icon2.Muestra(); cout << endl; objeto_icon1.Apariencia(":D"); objeto_icon1.Muestra(); objeto_icon2.Muestra(); return 0; } // Declara un objeto de tipo CEmoticon

Salida
:| :| :D :|

CEmoticon() { Apariencia(":|"); } La funcin CEmoticon() tiene el mismo nombre de la clase, por lo tanto es una funcin constructor y esta es llamada automticamente cuando se crean instancias de la clase. Ntese que en el cuerpo de la funcin constructor se llama la funcin miembro Apariencia(), aqu no se necesita el nombre del objeto, porque automticamente se usa el objeto que se este ejecutando (ver el operador this, al final de este capitulo)

En vez de llamar el mtodo Apariencia() la funcin miembro anterior se pudo haber escrito como: CEmoticon() { m_sIcon = ":|"; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

142

void Apariencia(string a_sIcon); A diferencia de la funcin miembro Muestra() la cual esta completamente implementada dentro de la clase (En forma inline, ver capitulo de subprogramas), aqu solo se incluye el encabezado de la funcin (El prototipo, ver capitulo de subprogramas) para indicar que pertenece a la clase, y la implementacin de la misma se realiza fuera de la declaracin de la clase. El anlisis de esta manera de crear las clases se discute en el siguiente tema en este capitulo: Clases y mdulos.

void CEmoticon::Apariencia(string a_sIcon) { m_sIcon = a_sIcon; }


Usando el nombre de la clase CEmoticon y el operador de alcance :: se implementa la funcin Apariencia() fuera de la declaracin de la clase.

CEmoticon objeto_icon1; CEmoticon CEmoticon objeto_icon2;

// Declara un objeto de tipo

Al declarar los objetos objeto_icon1 y objeto_icon2 se llama automticamente la funcin constructor CEmoticon().

objeto_icon1.Muestra(); objeto_icon2.Muestra();
Muestra el contenido de cada objeto, a diferencia del ejemplo anterior esto se hace sin antes llamar la funcin Apariencia() gracias a que el constructor ha inicializado la variable miembro m_sIcon al crear los objetos.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

143

Ejercicio Discuta cuales son las ventajas y desventajas de usar constructores como inicializadores de las variables miembro.

Clases y mdulos Al disear una clase es conveniente separar la interfase de la implementacin, la interfase dice aqu est como es el objeto y estos son los mtodos del objeto, la implementacin muestra cmo los mtodos trabajan [Eckel 1993] La declaracin de la clase es la interfase en C++, que a excepcin de las funciones implementadas dentro de la clase, solo indica cmo es el objeto. La prctica en C++ es escribir la declaracin de la clase en un archivo de encabezado y la implementacin en un archivo con extensin cpp. La siguiente aplicacin muestra una clase con una funcin constructor con argumentos y cmo mandarle los argumentos al constructor al crear el objeto; tambin sigue la prctica comn en C+ + de crear un archivo de encabezado con la especificacin de la clase y un archivo de cdigo (.cpp) con la implementacin de la clase. Listado // cfecha.h // clase implementada con mdulos // un constructor con #pragma once class CFecha { private: int mm, dd, aa; public: CFecha(int a_dd, int a_mm, int a_aa) { mm = a_mm; dd = a_dd; aa = a_aa; } void Fecha(); void FechaCompleta(); }; argumentos

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

144

CFecha(int a_dd, int a_mm, int a_aa) {


Se implementa el constructor con argumentos. Listado // cfecha.cpp // Implementacion de la clase cfecha #include "cfecha.h" #include <iostream> using namespace std; void CFecha::Fecha() { cout << dd << '/' << } void CFecha::FechaCompleta() { char *meses[] = { "Enero", "febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" }; cout << dd << " de " << meses[mm-1] << " del " << (2000 + aa); } En este archivo se implementan dos de las funciones miembro de la clase definida en el archivo de encabezado, esto permite incluir la clase en varias aplicaciones ya que la funcin main() no est en este archivo. mm << '/'<< aa;

char *meses[] = { "Enero", "febrero", "Marzo", "Abril", "Mayo", "Junio", };


Declara un arreglo de cadenas de caracteres y se inicializa con los nombres de los meses del ao.

"Julio", "Agosto",

"Septiembre", "Octubre", "Noviembre", "Diciembre"

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

145

cout << dd << " de " << meses[mm-1] << " del " << (2000 + aa);
Despliega la fecha completa usando las variables con el numero de da, el numero de mes como ndice del arreglo de nombres de los meses (menos uno ya que los arreglos en C++ empiezan en cero) y el numero de ao mas el milenio meses[mm-1] (claro que esta clase solo es til si se utiliza en este milenio, pero espero que para entonces salga una edicin nueva de este libro con los ajustes necesario ) Listado // testcfecha.cpp #include <iostream> #include "cfecha.h" using namespace std; int main() { CFecha f1(10, 1, 9); CFecha f2(15, 1, 10); f1.Fecha(); cout << "\t\t"; f1.FechaCompleta(); cout << endl; f2.Fecha(); cout << "\t\t"; f2.FechaCompleta(); return 0; }

Salida 10/1/9 15/1/10 10 de Enero del 2009 15 de Enero del 2010

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

146

CFecha f1(10, 1, 05);


Se declara el objeto f1, ya que el constructor tiene argumentos se le tiene que mandar los datos necesarios al declararlo, si el constructor no tuviera argumentos la declaracin seria solo CFecha f1.

Destructores Un destructor es una funcin miembro con el mismo nombre que la clase, pero precedido por un carcter tilde ~. Una clase slo tiene una funcin destructor, no tiene argumentos y no devuelve ningn valor. Al igual que las dems funciones miembro puede estar definido dentro o fuera de la clase. El destructor es usado para realizar las operaciones necesarias para el objeto cuando este deja de existir, como por ejemplo liberar espacio adquirido durante el tiempo de vida del objeto. El siguiente programa es una modificacin del ejemplo emoticon2.cpp presentado en el listado 7.2. Se usa un destructor y se muestra el orden de llamado del constructor y el destructor.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

147

Listado // emoticon_con.cpp // uso de constructores y destructores #include <iostream> using namespace std; class CEmoticon { private: string m_sIcon; public: CEmoticon(string a_sIcon); ~CEmoticon() { cout << endl << "Adios mundo cruel! " << m_sIcon; } void Muestra(void){ cout << endl << "Yo estoy " << m_sIcon; } }; CEmoticon::CEmoticon(string a_sIcon) { m_sIcon = a_sIcon; cout << endl << "Acabo de nacer! " << m_sIcon; } int main(){ CEmoticon emoticon1(":)"); { CEmoticon emoticon2(":("); emoticon2.Muestra(); } emoticon1.Muestra(); return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

148

Salida
Acabo de nacer! :) Acabo de nacer! :( Yo estoy :( Adios mundo cruel! :( Yo estoy :) Adios mundo cruel! :)

~CEmoticon() { cout << ende << "Adios mundo cruel! " << m_sIcon; }
Aqu se implementa el destructor el cual solo despliega un mensaje para anunciar que ha sido llamado, igual que el constructor.

main(){ CEmoticon emoticon1(":)"); { CEmoticon emoticon2(":|"); emoticon2.Muestra(); } emoticon1.Muestra() }


En la funcin principal se crean dos objetos, uno en el bloque de cdigo de la funcin main() CEmoticon emoticon1(":)") ; y el otro dentro de un bloque de cdigo para mostrar la creacin y destruccin de los objetos como se observa en la salida del programa.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

149

Miembros estticos
Al crearse un objeto, se separa espacio para las variables por cada objeto creado, a excepcin de las variables miembro estticas; stas pertenecen a todos los objetos derivados de la clase. Las variables estticas son globales para todos los objetos de la misma clase; stas variables tambin son llamadas variables de la clase ya que su contenido no depende de cada objeto. Una clase puede contener datos y funciones estticas. Los siguientes tres listados de cdigo presentan una aplicacin donde dentro de un ciclo se crean aleatoriamente varios objetos dentro de un arreglo de punteros, se muestran los objetos creados y despus se destruyen; todo esto llevando un conteo de los objetos creados y destruidos en una variable miembro de tipo static. Listado // static_emoticon.h // miembros estaticos // definicin clase CEmoticon #pragma once #include <string> using namespace std; class CEmoticon { private: static int m_iPoblacion; string m_sIcon; public: CEmoticon(string a_sIcon); ~CEmoticon(); static int Poblacion() { return m_iPoblacion; } void Muestra(); };

static int m_iPoblacion;


Se declara una variable miembro de tipo static. Listado // static_emoticon.cpp // implementacion de CEmoticon con miembros estaticos #include <iostream>

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

150

#include "static_emoticon.h" int CEmoticon::m_iPoblacion = 0; CEmoticon::CEmoticon(string a_sIcon) { m_iPoblacion++; m_sIcon = a_sIcon; } CEmoticon::~CEmoticon() { m_iPoblacion--; } void CEmoticon::Muestra() { cout << " " << m_sIcon; }

int CEmoticon::m_iPoblacion = 0;
Como la variable tipo static pertenece a la clase y no a un objeto en particular se inicializa haciendo referencia a la clase.

m_iPoblacion++;
La variable se incrementa dentro del constructor; como el constructor se llama cada vez que se crea un objeto, se lleva un conteo de los objetos en esta variable.

m_iPoblacion--;
La variable se decrementa cada vez que un objeto ejecuta al destructor el cual se llama automticamente cada vez que el objeto se destruye. Listado // test_static_emoticon.cpp // prueba la clase CEmoticon incluida en static_emoticon.cpp #include <iostream> #include <string> #include <cstdio> #include <ctime> #include "static_emoticon.h"

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

151

int main(){ int nc, i; CEmoticon *emoticon[10]; string op; nc = 0; srand((unsigned)time( NULL )); do { nc = rand() % 10; for (i = 0; i < nc; i++) emoticon[i] = new CEmoticon(":)"); cout << "Poblacion: " << CEmoticon::Poblacion() << endl; for (i = 0; i < nc; i++) emoticon[i]->Muestra(); for (i = 0; i < nc; i++) delete emoticon[i]; cout << endl << "Continuar (s/n) ?"; cin >> op; } while (op != "n" && op != "N"); return 0; } Salida Poblacion: 2 :) :) Continuar (s/n) ?s Poblacion: 9 :) :) :) :) :) :) :) :) :) Continuar (s/n) ?s Poblacion: 6 :) :) :) :) :) :) Continuar (s/n) ?n

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

152

CEmoticon *emoticon[10];
Se declara un arreglo de punteros de tipo CEmoticon, note que aqu no se crean los objetos, solo el espacio para almacenar diez direcciones a diez objetos del tipo CEmoticon.

nc = rand() % 10;
Dentro del ciclo se genera un nmero aleatorio entre el cero y nueve, para crear esta cantidad de objetos y guardar sus direcciones en el arreglo de punteros.

for (i = 0; i < nc; i++) emoticon[i] = new CEmoticon(":)");


Se crean los objetos dentro de un ciclo for: controlado por el numero generado aleatoriamente.

cout << "Poblacion: " << CEmoticon::Poblacion() << "\n";


Una vez que se han creado los objetos se despliega la variable esttica llamando la funcin miembro Poblacin().

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

153

for (i = 0; i < nc; i++) emoticon[i]->Muestra();


Despliegan los strings que contienen los objetos recin creados.

for (i = 0; i < nc; i++) delete emoticon[i];


Los objetos se destruyen. Las siguientes lneas controlan si se desea continuar dentro del ciclo principal; de ser as, todos los objetos habrn sido destruidos y se volver a empezar en cero objetos creados.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

154

Capitulo 5
Herencia

5.1 Importancia de la herencia en la POO


La herencia es una manera de reutilizar cdigo al crear clases nuevas en base a otras que ya existen, esto ahorra tiempo de desarrollo al utilizar cdigo probado anteriormente. Utilizando la herencia el desarrollador puede decidir que partes de la clase reutiliza y cuales implementa nuevamente para que se ajusten a las necesidades de la nueva clase. Hay que notar que no todos los miembros de la clase pueden ser heredados, los constructores, el destructor, los operadores de asignacin y los miembros estticos no son heredables.

5.2 Jerarqua de herencia


Al usar la herencia se forma con las clases derivadas estructuras jerrquicas en forma de rbol. A la clase que va ser heredada se le llama clase base, superclase o clase padre y a la clase que hereda se le llama clase derivada, subclase o clase hijo. Mediante el uso de la jerarqua se implementa una relacin de especializacin/generalizacin entre clases.

5.2.1 Conceptos de herencia simple y mltiple


Herencia simple La herencia simple significa que una clase es derivada de una sola clase a la vez.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

156

Por ejemplo si se quiere realizar un programa para dibujar figuras, se puede empezar por el elemento principal que todo dibujo contiene, un punto, de ah una lnea, un rectngulo, etc., y se va reutilizando el cdigo ya escrito de la clase anterior. Ejemplo:

Donde: 1. La clase lnea hereda de clase punto 2. La clase rectngulo hereda de clase lnea (y a la vez de punto a travs de lnea) Herencia mltiple La herencia mltiple es cuando una clase se deriva de ms de una a la vez y hereda las caractersticas de todas las clases de donde se deriva. Ejemplo:

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

157

Donde: 1. La clase CTiempo hereda de la clase CFecha y de clase CHora

5.2.2 Principios generales de diseo de jerarquas


La jerarqua se debe empezar desde lo ms genrico hasta lo ms especfico. Cada nivel de la jerarqua debe reutilizar cdigo del nivel anterior y extender la clase o clases de las cuales heredo. Ejemplo:

Solo los elementos de la clase que sean absolutamente necesarios para la comunicacin externa de los objetos deben de ser de tipo puiblic. Los miembros que solo sean necesarios para las clases derivadas deben marcarse como protected. Todos los dems miembros de la clase deben ser de tipo private, esto es para encapsular el objeto y reducir al mnimo los conflictos de acceso a los mismos, as como para aumentar la flexibilidad del mantenimiento de la clase, al no estar expuestos es mas fcil cambiarlos, ya sea de tipo de datos, nombres, etc. Lo recomendable es hacer o seguir un anlisis y diseo orientado a objetos antes de empezar a codificar.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

158

5.2.3 Especificadores de acceso a jerarqua de clases


Al crear una clase se cuenta con un control de acceso a los miembros de la misma que son private, protected y public, este control se puede restringir an mas al derivar. Dependiendo del tipo de acceso con que cuenten los miembros de la clase base estos son cambiados de acuerdo al modificador de acceso impuesto al derivarse. Si al heredar se usa el modificador de acceso: private Los miembros de la clase base que sean: private protected protected public private protected public public private protected public Su acceso en la clase derivada es: Inaccesible private private Inaccesible protected protected Inaccesible protected public

5.3 Definicin de una clase base


Cualquier clase puede ser una base clase, inclusive una clase derivada puede servir como clase base para subsecuentes derivaciones. La sintaxis para definir clases bases es igual a definir clases ordinarias, solo que ahora se debe declarar como protected los miembros que se quiere que sean heredados por las clases derivadas. Tomar en cuenta la tabla anterior para asegurarse que las clases derivadas cuenten con el acceso debido a los miembros de la clase base. Se puede crear una clase con el solo propsito de ser heredada, a este tipo de clases se les llama clases abstractas. Listado // cbase.h // ejemplo de tipos de acceso para usar en la herencia #pragma once #include <string> using namespace std; class CBase {

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

159

private: string strPrivado; protected: string strProtegido; public: string strPublico; CBase(){ strPrivado = "Privado, dominio de esta clase"; strProtegido = "Protegido, dominio de la familia"; strPublico = "Publico, dominio publico"; } }; Esta clase contiene los tres tipos de acceso y servir como base para ser heredada mas adelante, as como para mostrar el tipo de acceso de los miembros al usarla. Listado // testcbase.cpp #include "cbase.h" #include <iostream> using namespace std; int main(){ CBase base; //cout << base.strPrivado << endl; cout << base.strPublico << endl; return 0; } Salida Publico, dominio publico // no accesible // accesible porque es publico

//cout << base.strProtegido << endl; // no accesible

Note que el campo miembro de tipo protected acta como tipo private para la clase base.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

160

Listado // CJugadorVirtual.h // clase base, para ser heredada por otra // los objetos generan un numero aleatorio entre // 0 y 9 #pragma once #include <iostream> #include <cstdlib> // rand() #include <ctime> using namespace std; class CJugadorVirtual { protected: int numero; public: CJugadorVirtual() { numero = 0; } void Adivina() { numero = rand() % 10; } int MiNumero() { return numero; } }; protected: int numero; Aqu se declara un entero con control de acceso protegido, cada objeto debe generar un numero aleatorio al llamar el mtodo Adivina() y regresar el numero con el mtodo MiNumero(), la idea es que sea parte de un jugador artificial dentro de un programa y a la vez servir como base para una clase que represente a un jugador humano.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

161

Listado // test_jugadorvirtual.cpp // se genera un numero aleatorio en la funcion main // y los objetos CJugadorVirtual "juegan" a // "adivinar" el numero generado en main #include <iostream> #include <cstdlib> // srand() #include <ctime> // time() #include "CJugadorVirtual.h" using namespace std; int main() { bool adivinado = false; int numeroGenerado; CJugadorVirtual j1; CJugadorVirtual j2; srand((unsigned)time( NULL )); numeroGenerado = rand() % 10; cout << "Estoy pensando en un numero entre 0 y 9..." << endl; while (true) { j1.Adivina(); j2.Adivina(); cout << endl << "Jugador uno dice " << j1.MiNumero(); cout << endl << "Jugador dos dice " << j2.MiNumero(); if (j1.MiNumero() == numeroGenerado) adivinado = true; if (j2.MiNumero() == numeroGenerado) adivinado = true; if (adivinado){ cout << endl << "Numero Adivinado!, el numero era "

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

162

<< numeroGenerado; break; } else cout << endl << "Los jugadores deben de intentar otra vez.\n"; } return 0; } Salida Estoy pensando en un numero entre 0 y 9... Jugador uno dice 9 Jugador dos dice 9 Los jugadores deben de intentar otra vez. Jugador uno dice 1 Jugador dos dice 4 Numero Adivinado!, el numero era 1

El programa genera un nmero aleatorio y usa la clase CJugadorVirtual para crear objetos que generen nmeros y compararlos con el nmero generado dentro de main, esto para crear un juego de adivina el nmero que pienso, en este caso no hay intervencin externa y los programas juegan solos. Ejercicios 3.Modifique la siguiente clase para ser usada como clase base, siguiendo los principios de diseo de la programacin orientada a objetos, tip: es una sola lnea la que hay que modificar. // cpersona.h // Ejercicio modificar para ser clase base #pragma once #include <iostream> #include <string> using namespace std; class CPersona {

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

163

private: string Nombre; string Direccion; string Telefono; public: void Captura(void); void Despliega(void); }; void CPersona::Captura(void) { cout << endl << "Nombre : "; getline(cin, Nombre, '\n'); cout << "Direccion: ";

getline(cin, Direccion, '\n'); cout << "Telefono : "; getline(cin, Telefono, '\n'); } void CPersona::Despliega(void) { cout << endl << Nombre; cout << endl << Direccion; cout << endl << Telefono; } 2. Realice un programa principal para que pruebe la clase CPersona

5.4 Definicin de una clase derivada


Una clase derivada hereda la capacidad para llamar a funciones miembro de la clase base en los objetos de la clase derivada. Forma general: class clase_derivada : modificador_de_acceso clase_base { };

5.4.1 Constructores y destructores de clases derivadas


Si la clase derivada no cuente con constructores, utiliza los de la clase base, en igual forma con el destructor. En caso de que cuente con constructor o destructor debe estar coordinado con el constructor y destructor de la clase base. El constructor de la clase derivada debe llamar al constructor de la clase base y enviar los valores requeridos por el constructor de la clase base.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

164

Si la clase base y la clase derivada cuentan con un constructor primero de ejecuta el constructor de la clase base y despus el de la clase derivada. El orden de llamado de inicializacin de las clases en la jerarqua de herencia es primero las clases base de una clase derivada. En el caso del destructor el orden de ejecucin es inverso, primero la clase derivada y despus las clases base.

5.4.2 Conversin implcita de objetos de clase derivada a objeto de clase base


Un objeto de la clase derivada se convierte en forma implcita en un objeto de la clase base pblica. Una referencia a una clase derivada se convierte implcitamente en una referencia a la clase base pblica. Un puntero a la clase derivada se convertir implcitamente en un puntero a la clase base. Un puntero a un miembro de una clase base se convertir en forma implcita en un puntero a miembro de la clase derivada. Adicionalmente, un puntero a cualquier objeto ser implcitamente convertido en un puntero del tipo void * (Para asignar este a un puntero a otro tipo hace falta el uso de cast explcito.)

Listado // hereda_cbase.cpp // ejemplo de tipos de acceso herencia #include <iostream> #include <string> #include "cbase.h" using namespace std; // Derivando en forma privada class CDerivadaPrivada : private CBase { public: void Despliega() { // no accesible, privado solo lo puede usar "CBase" // cout << strPrivado << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

165

cout << strProtegido << endl; cout << strPublico << endl; } }; // Derivando en forma protegida class CDerivadaProtegida : protected CBase { public: void Despliega() { // no accesible, privado solo lo puede usar "CBase" // cout << strPrivado << endl; cout << strProtegido << endl; cout << strPublico << endl; } }; // Derivando en forma publica class CDerivadaPublica : public CBase { public: void Despliega() { //cout << strPrivado << endl; cout << strProtegido << endl; cout << strPublico << endl; } }; int main(){ CDerivadaPrivada privada; privada.Despliega(); // no accesible al heredar se uso "private", // y un publico se convierte en privado // cout << privada.strPublico << endl; CDerivadaProtegida protegida; protegida.Despliega(); // no accesible al heredar se uso "protected", // un publico se convierte en potegido // cout << protegida.strPublico << endl;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

166

CDerivadaPublica publica; publica.Despliega(); // accesible al heredar se uso "public", // un publico se queda como publico cout << publica.strPublico << endl; return 0; } Salida Protegido, dominio de la familia Publico, dominio publico Protegido, dominio de la familia Publico, dominio publico Protegido, dominio de la familia Publico, dominio publico Publico, dominio publico

#include "cbase.h" La clase CBase se incluye con aqu. class CDerivadaPrivada : private CBase { En esta lnea se hereda en forma privada la clase Cbase y la clase CDerivadaPrivada obtiene derecho a todos los miembros permitidos de la clase CBase como si fueran incluidos directamente en la clase derivada. class CDerivadaProtegida : protected CBase { class CDerivadaPublica : public CBase { En estas lneas se hereda de la clase CBase en forma protegida y publica respectivamente obteniendo el acceso a los miembros de la clase CBase segn las reglas de acceso y se pueden usar como de la misma manera que los miembros propios. En la funcin principal main() se crean objetos de las tres clases derivadas de CBase y se prueban sus miembros para mostrar el acceso que se obtiene con los diferentes controles de acceso al heredar.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

167

Listado // CJugadorHumano.h #pragma once #include <iostream> #include "CJugadorVirtual.h" using namespace std; class CJugadorHumano : public CJugadorVirtual { public: void Adivina() { cout << " Numero que piensas? "; cin >> numero; } };

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

168

class CJugadorHumano : public CJugadorVirtual { En esta lnea la clase CJugadorHumano hereda pblicamente a la clase CJugadorVirtual obteniendo el acceso a todos sus miembros permitidos. protected: int numero; El campo numero es heredado y se vuelve de tipo protected para que pueda ser heredado en clases derivadas si as se necesitara. El acceso esta garantizado para la clase CJugadorHumano como si fuera escrito directamente en la clase. CJugadorVirtual() { int MiNumero() { Estos mtodos son heredados tal y como estn, ya que la el constructor CJugadorVirtual() no usa argumentos este se manda llamar automticamente y no es necesario tomar medidas dentro de la clase derivada. void Adivina() { En el caso de este mtodo, se sobre-escribe ya que la implementacin del mtodo dentro de la clase CJugadorVirtual no se aplica para esta clase y es necesario pedir el numero al usuario. Al sobrescribir este mtodo la clase derivada desecha el uso del mtodo de la clase base, al menos automticamente, ya que aun puede ser llamado indicando el nombre de la clase base, por ejemplo: CBase::Adivina() y ejecutara le mtodo de la clase padre en ve del mtodo propio. Listado // JuegoAdivina3.cpp #include <iostream> #include <ctime> #include <cstdlib> #include "CJugadorHumano.h" using namespace std; int main() { bool adivinado = false; int numeroGenerado; CJugadorVirtual j1; CJugadorVirtual j2; CJugadorHumano jh;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

169

srand((unsigned)time( NULL )); numeroGenerado = rand() % 10; cout << "Estoy pensando en un numero entre 0 y 9..." << endl; while (true) { j1.Adivina(); j2.Adivina(); jh.Adivina(); cout << endl << "Jugador uno dice " << j1.MiNumero(); cout << endl << "Jugador dos dice " << j2.MiNumero(); cout << endl << "Jugador tres dice " << jh.MiNumero(); if (j1.MiNumero() == numeroGenerado) adivinado = true; if (j2.MiNumero() == numeroGenerado) adivinado = true; if (jh.MiNumero() == numeroGenerado) adivinado = true; if (adivinado){ cout << endl << "Numero Adivinado!, el numero era " << numeroGenerado; break; } else cout << endl << "Los jugadores deben de intentar otra vez.\n"; } return 0; } Salida Estoy pensando en un numero entre 0 y 9...

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

170

Numero que piensas? 3 Jugador uno dice 7 Jugador dos dice 6 Jugador tres dice 3 Los jugadores deben de intentar otra vez. Numero que piensas? 4 Jugador uno dice 1 Jugador dos dice 1 Jugador tres dice 4

Este ejemplo es casi idntico al del programa test_jugadorvirtual.cpp con la diferencia que se crea un objeto de tipo CJugadorHumano y este objeto permite la participacin externa al preguntar por un nmero para comparar con el generado en el programa principal. Ejercicios 4 Realic una clase derivada de la clase CPersona, la cual se sugiere se llame CEstudiante que adems contenga los siguientes miembros: string numero_control int calificacion Mtodo Captura() Debe de capturar tanto los campos heredados como los propios. Mtodo Despliega() Debe de desplegar en pantalla tanto los campos heredados como los propios. Mtodo RegresaCalificacion() - regresar la calificacin 2. Realice un programa principal para que pruebe la clase CEstudiante

5.5 Herencia mltiple


Forma general: class clase_derivada : modificador_de_acceso clase_base, modificador_de_acceso clase_base2, { };

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

171

La siguiente clase es para usarla como una de las clases padres en el ejemplo de herencia mltiple; es una modificacin a la clase de CFecha mostrada en el capitulo de clases, la modificacin consiste en inicializar las variables que representan la fecha desde el sistema. Listado // autofecha.h // clase CFecha, el constructor toma la fecha del sistema #pragma once #include <iostream> #include <time> using namespace std; class CFecha { protected: int mm, dd, aa; public: CFecha(){ time_t ahora = time(NULL); dd = tiempo->tm_mday; mm = tiempo->tm_mon + 1; aa = tiempo->tm_year - 100; } void Despliega() { cout << dd << '/' << } }; mm << '/'<< aa; // Hora y fecha de hoy struct tm *tiempo = localtime(&ahora);

time_t ahora = time(NULL); // lee la fecha/hora del sistema Se asigna el tiempo que regresa la funcin time(), al incluir el NULL como argumento esta funcin regresa el tiempo actual del sistema.

struct tm *tiempo = localtime(&ahora); tm es una estructura para almacenar informacin correspondiente a varias funciones de manejo del tiempo.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

172

La funcin localtime() acomoda la informacin del la variable ahora para que se formatee el tiempo para ser desplegado.
En las siguientes lneas se asignan las variables miembro de la estructura tiempo a las variables miembro de la clase, que son dd, mm y aa. La siguiente clase es para usarla como una de las clases padres en el ejemplo de herencia mltiple, una clase para representar la hora la inicializacin de las variables es desde el sistema.

Listado // autohora.h // clase CHora, el constructor toma la hora del sistema #pragma once #include <iostream> #include <time> using namespace std; class CHora { protected: int hh, mm, ss; public: CHora(){ time_t ahora = time(NULL); hh = tiempo->tm_hour; mm = tiempo->tm_min; ss = tiempo->tm_sec; } void Despliega() { cout << hh << ':' << } }; mm << ':'<< ss; // Hora y fecha de hoy struct tm *tiempo = localtime(&ahora);

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

173

La diferencia entre esta clase y la de CFecha es que se asignan las variables de la estructura tiempo correspondientes a la hora a las variables miembro de la clase, que son hh, mm y ss.

El siguiente ejemplo implementa la Clase CTiempo y esta hereda de dos clases CFecha y CHora. Listado // tiempo.h // Clase CTiempo, ejemplo de multiple herencia #include "autofecha.h" #include "autohora.h" class CTiempo : public CFecha, public CHora { public: void Despliega(){ CFecha::Despliega(); cout << " "; CHora::Despliega(); } void CambiaFecha(int ad, int am, int aa) { dd = ad; CFecha::mm = am; aa = aa; } void CambiaHora(int ah, int am, int as) { hh = ah; CHora::mm = am; ss = as; } };

#include "autofecha.h" #include "autohora.h"


Se incluyen los archivos de encabezado donde se encuentran las clases de CFecha y CHora.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

174

class CTiempo : public CFecha, public CHora {


Se define la clase CTiempo y hereda de CFecha y de CHora, especificando el modificador de acceso y separadas ambas por comas; sta clase no tiene variables miembro por s misma solo utiliza las variables de las clases de las que se deriva.

void Despliega(){ CFecha::Despliega(); cout << " "; CHora::Despliega(); }


En la implementacin de la funcin Despliega() se imprime en pantalla la fecha y la hora, aqu como ambas clases de las que hereda CTiempo cuentan con una funcin Despliega(), se utiliza el operador de acceso :: para especificar de cual clase se usa la funcin Despliega().

void CambiaFecha(int ad, int am, int aa) { dd = ad; CFecha::mm = am; aa = aa; }
En este mtodo se actualizan las variables. Ntese que las clases CFecha y CHora cuentan con una variable que se llama igual por lo tanto es necesario utilizar el operador de acceso para indicarle al compilador a cual clase pertenece la variable. El siguiente programa hace uso de la clase creada en el programa anterior. Listado // testTiempo.cpp // Prueba la clase con herencia multiple CTiempo #include "tiempo.h" int main(){ CFecha fecha; fecha.Despliega(); cout << endl; CHora hora; hora.Despliega();

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

175

cout << endl; CTiempo tiempo; tiempo.Despliega(); tiempo.CambiaHora(12, 10, 20); cout << endl; tiempo.Despliega(); return 0; }

Salida
19/6/9 16:50:6 19/6/9 16:50:6 19/6/9 12:10:20

La utilizacin de la clase CTiempo es idntica a los dems ejemplos donde se declaran objetos, independientemente de si fue una clase sola o s uso herencia simple o herencia mltiple.

Ejercicio 1 Discuta las ventajas y desventajas del uso de la herencia mltiple 2 Investigue que problemas se pueden presentar al usar herencia mltiple

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

176

Capitulo 6
Polimorfismo

6.1 Concepto de polimorfismo


En C++ es la propiedad de ejecutar funciones miembro (mtodos) de diferentes clases que pertenecen a una jerarqua formada mediante la herencia, esto se obtiene usando funciones virtuales y punteros a la clase base, este proceso se conoce como enlace dinmico. Tambin se puede implementar polimorfismo esttico a travs de la sobrecarga de funciones, lo cual es la propiedad de tener ms de una funcin miembro con el mismo nombre, donde cada funcin puede pude implementar un proceso diferente (ver mas en el capitulo 2, subprogramas, 2.7 Sobrecarga de subprogramas) El siguiente ejemplo muestra la sobrecarga de funciones, dos funciones constructor. Las funciones se pueden sobrecargar independientemente de si son parte de una clase o no. Listado // cpolifecha.h // clase implementada en mdulos, dos constructores #pragma once class CFecha { private: int mm, dd, aa; public: CFecha(); CFecha(int a_dd, int a_mm, int a_aa) { (c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

179

mm = a_mm; dd = a_dd; aa = a_aa; } void Fecha(); void FechaCompleta(); };

CFecha(); CFecha(int a_dd, int a_mm, int a_aa) {


Se declaran dos constructores con el mismo nombre pero uno sin argumentos y otro con tres argumentos.

Listado
// cpolifecha.cpp #include "cpolifecha.h" #include <iostream> #include <ctime> using namespace std; CFecha::CFecha(){ time_t ahora = time(NULL); dd = tiempo->tm_mday; mm = tiempo->tm_mon + 1; aa = tiempo->tm_year - 100; } void CFecha::Fecha() { cout << dd << '/' << } void CFecha::FechaCompleta() { string meses[] = {"Enero", "febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"}; mm << '/'<< aa; // Hora y fecha de hoy struct tm *tiempo = localtime(&ahora);

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

180

cout << dd << " de " << meses[mm-1] << " del " << (2000 + aa); } Listado // testcpolifecha.cpp #include <iostream> #include "cpolifecha.h" using namespace std; int main() { CFecha f1(10, 1, 15); CFecha f2; f1.Fecha(); cout << "\t\t"; f1.FechaCompleta(); cout << endl; f2.Fecha(); cout << "\t\t"; f2.FechaCompleta(); cout << endl; return 0; } Salida 10/1/15 1/6/9 10 de Enero del 2015 1 de Junio del 2009

CFecha f1(10, 1, 05); CFecha f2;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

181

Se declaran dos objetos de tipo CFecha, el primer objeto recibe 3 argumentos, por lo tanto el constructor con tres argumentos es llamado. En la siguiente lnea al declarar el objeto f2 se llama el constructor sin argumentos. Ejercicio 1 Discuta si es posible sobrecargar los mtodos Fecha() y FechaCompleta(). 2 Discuta cual son las posibles ventajas y desventajas de la sobrecarga de funciones miembro.

6.2 Clase base abstracta


Una clase base abstracta tiene funciones virtuales puras, es decir funciones que no son implementadas en la clase; este tipo de clases es para ser usada como clase base solo para ser derivada por otras clases y no para declarar instancias de la misma; al contener funciones virtuales es imposible que se creen objetos del tipo de la clase (aunque s se pueden crear punteros que hagan referencia a este tipo de clases). Si las clases derivadas no implementan las funciones virtuales puras, estas clases derivadas se convierten tambin en clases abstractas. Si las clases derivadas implementan todas las funciones virtuales puras se convierten en clases concretas y pueden ser usadas para instanciar objetos. Ejemplo: virtual void dibujar() = 0; El siguiente ejemplo implementa una clase abstracta y dos clases que se derivan de ella e implementan las funciones virtuales puras definidas en la clase abstracta. Listado // abstracta.h // ejemplo de clase con funciones virtuales puras #pragma once #include <iostream> #include <string> using namespace std; class CPersona { protected: string m_sNombre; public: virtual void Agrega() = 0;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

182

virtual void Muestra() = 0; }; class CEmpleado : public CPersona { protected: float m_fSalario; public: void Agrega() { cout << "Nombre "; cin >> m_sNombre; cout << "Salario "; cin >> m_fSalario; } void Muestra() { cout << "\nNombre " << m_sNombre; cout << "\nSalario " << m_fSalario; } }; class CSocio : public CPersona { protected: int m_iAcciones; public: void Agrega() { cout << "Nombre "; cin >> m_sNombre; cout << "Acciones "; cin >> m_iAcciones; } void Muestra() { cout << "\nNombre " << m_sNombre; cout << "\nAcciones " << m_iAcciones; } };

virtual void Agrega() = 0; virtual void Muestra() = 0;


(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 183

Aqui se declaran las funciones miembro como virtuales puras, esto le indica al compilador que estas funciones van a ser implementadas por las clases derivadas. Listado // testAbstracta.cpp // prueba la clae abstracta CPersona y sus clases derivadas #include "abstracta.h" int main(){ CPersona *persona; CEmpleado empleado; CSocio socio; cout << "\nAgrega los datos del empleado " << endl; empleado.Agrega(); cout << "\nAgrega los datos del socio " << endl; socio.Agrega(); persona = &empleado; persona->Muestra(); persona = &socio; cout << endl; persona->Muestra(); cout << endl; return 0; } Salida Agrega los datos del empleado Nombre Bruce Salario 150 Agrega los datos del socio Nombre Bjarne Acciones 33

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

184

Nombre Bruce Salario 150 Nombre Bjarne Acciones 33

En este ejemplo se declaran dos objetos uno de tipo CEmpleado y otro de tipo CSocio, un puntero a la clase base CPersona. El objeto empleado y el objeto socio mandan llamar sus funciones miembro de Agrega() para asignar valores a las variables miembro por medio de la entrada de datos del usuario, como se muestra en los dos primeros prrafos de la salida. Mediante el puntero se accesa indirectamente a los objetos y se despliega el contenido las variables miembro a travs de la funcin Muestra(). Ejercicio 5 Discuta si la clase abstracta en el ejemplo anterior podra no serlo y de ser as, porque. 6 Proponga situaciones donde sea til usar una clase abstracta.

6.3 Subprogramas virtuales


Las funciones virtuales son resueltas a la hora de ejecucin del programa (run time), mediante un mecanismo llamado ligamiento tardo (late-binding) De esta manera un objeto se puede manipular como si fuera genrico accesando los objetos derivados mediante el objeto base. Solo las funciones miembros pueden ser declaradas como virtual. Para declarar que una funcin de la clase base es virtual, a su prototipo se le antepone la palabra reservada virtual, esta palabra solo debe ser usada en la declaracin de la funcin, y no en la definicin de la funcin si se realiza fuera del cuerpo de la clase. Ejemplo: virtual void dibujar();

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

185

Para que el ligado tardo funcione, las funciones derivadas deben tener exactamente el mismo nombre, incluyendo el numero de argumentos y sus tipos de datos, de no ser as el mecanismo virtual es inoperable. Listado // virtual.h // ejemplo de clase con funciones virtuales #pragma once #include <iostream> #include <string> using namespace std; class CPersona { protected: string m_sNombre; public: virtual void Agrega() { cout << "Nombre "; cin >> m_sNombre; } virtual void Muestra() } }; class CEmpleado : public CPersona { protected: float m_fSalario; public: void Agrega() { CPersona::Agrega(); cout << "Salario "; cin >> m_fSalario; } void Muestra() { CPersona::Muestra(); cout << "\nSalario " << m_fSalario; } { cout << "\nNombre " << m_sNombre;

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

186

}; class CSocio : public CPersona { protected: int m_iAcciones; public: void Agrega() { CPersona::Agrega(); cout << "Acciones "; cin >> m_iAcciones; } void Muestra() { CPersona::Muestra(); cout << "\nAcciones " << m_iAcciones; } };

virtual void Agrega() {


Se declara (y empieza la implementacin) de la funcin miembro Agrega() en forma virtual, esto le indica al compilador que la resolucin de esta funcin sea resuelta en tiempo de ejecucin.

La clase CPersona a diferencia del ejemplo anterior no es mas una clase abstracta ya que todas los mtodos estn implementados.
Listado // testVirtual.cpp // prueba la clae abstracta CPersona y sus clases derivadas #include "virtual.h" int main(){ CPersona *persona; CPersona obj_persona; CEmpleado empleado; CSocio socio; cout << "\nAgrega los datos de una persona " << endl; obj_persona.Agrega();

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

187

cout << "\nAgrega los datos del empleado " << endl; empleado.Agrega(); cout << "\nAgrega los datos del socio " << endl; socio.Agrega(); // despliega los datos de obj_persona obj_persona.Muestra(); // Despliega los datos de empleado y socio mediante // el puntero persona persona = &empleado; persona->Muestra(); persona = &socio; cout << endl; persona->Muestra(); cout << endl; return 0; } Salida Agrega los datos de una persona Nombre Batman Agrega los datos del empleado Nombre Superman Salario 3500.50 Agrega los datos del socio Nombre Tarzan Acciones 33 Nombre Batman Nombre Superman

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

188

Salario 3500.5 Nombre Tarzan Acciones 33

CPersona obj_persona;
Aqu se declara un objeto de tipo CPersona, note que la clase CPersona del programa testAbstracta.cpp no puede ser usada para instanciar objetos ya que es una clase abstracta porque tiene funciones virtuales puras, no as en este ejemplo que las funciones virtuales estn plenamente implementadas. Nota: El uso de funciones miembro virtuales permite acceder a los mtodos virtuales de las clases derivadas usando indireccion mediante un puntero de tipo clase base. Los mtodos virtuales puros garantiza el acceso a los mtodos de las clases derivadas mediante la clase base aun cuando la clase base no cuente con suficientes datos para implementar tales mtodos.

6.4 Destructores virtuales


Los destructores virtuales son como todas dems funciones miembro, por ejemplo, si en una jerarqua de clases tiene destructores y se accesan los objetos de las clases derivadas mediante un puntero a la clase base, al momento de que un objeto es destruido y si el destructor de la clase base no es virtual, se llamara el destructor de la clase base y no a los dems destructores de la jerarqua. Cuando el destructor de la clase base es virtual y es llamado para destruir el objeto se llama a todos los destructores que estn hacia arriba en la jerarqua de la herencia. Como regla general, si en una clase existen funciones virtuales, el destructor debe ser virtual. Listado // destructor_virtual.cpp #include <iostream> using namespace std; class CBase {

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

189

public: // no virtual, posible problema // ~CBase() { virtual ~CBase() { cout << " Destruyendo CBase" << endl; } virtual void Metodo() { cout << "CBase::Metodo()" << endl; } }; class CDerivada1 : public CBase { public: ~CDerivada1() { cout << "Destruyendo CDerivada1" << endl; } void Metodo() { cout << "CDerivada1::Metodo()" << endl; } }; class CDerivada2 : public CDerivada1 { public: ~CDerivada2() { cout << " Destruyendo CDerivada2" << endl; } void Metodo() { cout << "CDerivada2::Metodo()" << endl; } }; main() { // puntero clase base a objeto derivado CBase * pBase = new CDerivada2; pBase->Metodo(); delete pBase; // llamada a funcin virtual // borrar puntero a clase base

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

190

return 0; } Salida sin destructor virtual CDerivada2::Metodo() Destruyendo CBase

Salida con destructor virtual CDerivada2::Metodo() Destruyendo CDerivada2 Destruyendo CDerivada1 Destruyendo CBase

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

191

Capitulo 7
Archivos

7.1 Clases de E/S Clase base abstracta


Stream es la clase base abstracta de E/S, esta es compatible con bytes de lectura y escritura. Todas las clases que representan secuencias se derivan de la clase Stream. La clase Stream y sus clases derivadas proporcionan una visin genrica de los orgenes de datos y de su almacenamiento.

Corrientes de flujo
El sistema de E/S de C++ proporciona una interfaz independiente del dispositivo real al que se accede; esto es una abstraccin entre el programador y el dispositivo que se usa. Esta abstraccin se llama corriente y el dispositivo real se llama archivo. Corrientes Almacenamiento temporal de archivo para transformar los dispositivos fsicos en un almacenamiento lgico. Esto permite que las corrientes sean independientes de los dispositivos. Existen dos tipos de corrientes: texto y binarias.

7.2 Realizar entrada y salida de texto


Archivos de texto Las corrientes de texto son una secuencia de caracteres organizadas en lneas terminadas por un carcter nueva lnea. La traduccin del carcter nueva lnea depende de la implementacin.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

193

Entrada de texto La entrada o tambin llamada lectura es la transferencia de datos desde una secuencia a una estructura de datos, como, por ejemplo, una matriz de bytes. Salida de texto La salida, tambin llamada escritura consiste en la transferencia de informacin desde un origen de datos a una secuencia. Operaciones de bsqueda Las operaciones de bsqueda consisten en la consulta y modificacin de la posicin actual en una secuencia.

7.3 Leer y escribir archivos


En el archivo fstream estn definidas varias clases de entrada y salida, incluyendo ifstream flujo de entrada, ofstream flujo de salida. Para leer y/o escribir en un archivo se crea un objeto de tipo fstream. Forma general: fstream objeto(nombre_archivo, modo); Donde modo es: ios::in ios::out ios::out | ios::trunc ios::out | ios::app ios::out | ios::in ios::in | ios::out | ios::trunc ios::in | ios::out | ios::app ios::binary abre archivo existente para lectura abre archivo para escritura crea archivo para escritura o trunca el archivo existente abre archivo existente para agregar abre archivo existente para lectura y escritura trunca el archivo existente o crea archivo para lectura y escritura abre el archivo existente o crea archivo para lectura y escritura para archivos binarios

Lectura de un archivo de texto Se crea el objeto con fstream nombre_del_objeto, indicando que es de lectura con el manipulador ios::in. Ejemplo:

fstream entrada(archivo.txt, ios::in); Listado

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

194

// muestra.cpp // ejemplo de lectura de un archivo de texto // muestra un archivo de texto en la salida estandard #include <iostream> #include <fstream> #include <cstdlib> using namespace std; int main() { char szArchivo[20]; char c; cout << "Archivo a mostrar? "; cin >> szArchivo; fstream entrada(szArchivo, ios::in); if (entrada.fail()) { cout << "Error al abrir archivo! Abortando"; exit(1); } while (!entrada.eof()){ entrada.get(c); cout << c; } entrada.close(); return 0; } Salida Archivo a mostrar? primer.cpp // Primer.cpp // Escribe un mensaje en pantalla #include <iostream> using namespace std; int main() // termina la ejecucion del programa

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

195

{ cout << "Este es mi primer programa en C++"; return 0; }

fstream entrada(szArchivo, ios::in); Se crea el objeto de tipo fstream, y se intenta abrir el archivo que indica la cadena de caracteres szArchivo; el manipulador ios::in indica abrirlo en modo solo lectura. La informacin sobre el xito o fracaso se almacena en basic_ios:rstate. if (entrada.fail()) {
La funcin miembro fail(), regresa el numero uno o true o bien un cero o false dependiendo de la informacin en basic_ios::rstate. En caso de error de creacin del objeto termina la ejecucin del programa al llamar la funcin exit().

while (!entrada.eof()){ eof(), regresa un cero o false si no se ha alcanzado el final del archivo y uno o trae si esta en el fin de archivo. entrada.get(c); get(), lee un carcter del flujo de entrada y lo asigna a la variable c. entrada.close(); close(), cierra el archivo.
Ejercicio

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

196

Escriba un programa que lea un archivo de texto y lo despliegue en maysculas en la salida estndar.

Escritura en un archivo de texto Para escribir en un archivo se crea un objeto de tipo fstream, con la sentencia fstream nombre_del_objeto, indicando que es de escritura con el manipulador ios::out. Al crear el objeto, si el archivo fsico no existe se crea fsicamente en blanco, si ya existe se sobrescribe en blanco. Ejemplo:

fstream salida(archivo.txt, ios::out);


El siguiente programa de ejemplo lee un archivo de texto y la va escribiendo en otro archivo de texto pero en forma encriptada. La tcnica usada para encriptar el archivo se basa en desfasar en uno cada carcter. Ejemplo: Teniendo la cadena: HOLA
H O L A \0

El correspondiente cdigo ascii para cada letra es:


72 48 76 64 \0

Si se le suma un uno a cada cdigo: 72 = H 72 + 1 = 73 73 = J Toda la cadena en ascii con cada elemento incrementado en uno:
73 49 77 65 \0

Por lo tanto la cadena queda como: J1MB


J 1 M B \0

Para desencriptarla solo hay que restarle uno a cada elemento.

Listado
// encripta.cpp // ejemplo de lectura y de escritura a archivos de texto. // lee un archivo de entrada, desfasa el caracter leido y

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

197

// lo escribe en el archivo de salida #include <iostream> #include <fstream> #include <cstdlib> using namespace std; int main() { char szEntrada[20]; char szSalida[20]; char c; cout << "Archivo a encriptar? "; cin >> szEntrada; cout << "Guardar archivo encriptado en? "; cin >> szSalida; fstream entrada(szEntrada, ios::in); fstream salida(szSalida, ios::out); if (entrada.fail()) { cout << "Error al abrir archivo de entrada! Abortando"; exit(1); } if (salida.fail()) { cout << "Error al abrir archivo de salida! Abortando"; exit(1); } while (!entrada.eof()){ entrada.get(c); salida.put(c+1); } entrada.close(); salida.close(); return 0; } Salida // encripta

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

198

Archivo a encriptar? primer.cpp Guardar archivo encriptado en? primer.txt

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

199

Nota, Listado del archivo primer.txt: 00!Qsjnfs/dqq 00!Ftdsjcf!vo!nfotbkf!fo!qboubmmb $jodmvef!=jptusfbn? vtjoh!obnftqbdf!tue< jou!nbjo)* | !!!dpvu!==!#Ftuf!ft!nj!qsjnfs!qsphsbnb!fo!D,,#< !!!sfuvso!1< ~

fstream entrada(szEntrada, ios::in); fstream salida(szSalida, ios::out);


Se crean y se abren los archivos de entrada y de salida.

while (!entrada.eof()){ entrada.get(c); salida.put(c+1); }


Se recorre el archivo de entrada leyendo carcter por carcter y se escribe en la salida sumndole un uno para encriptarlo.

// encripta

entrada.close(); salida.close();
La llamada al mtodo close() cierra el archivo.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

200

Ejercicios 4.Escriba un programa que lea un archivo de texto y lo escriba en un nuevo archivo de texto copie el contenido de un archivo de texto existente en otro. 5.Desarrolle un programa que lea una cadena de caracteres y la grabe en un archivo de texto. 6.Modifique el programa encripta.cpp para que desencripte un archivo.

Lectura y Escritura en un archivo de texto Para modificar un archivo (leer y escribir en un mismo archivo) se crea un objeto de tipo fstream, con la sentencia fstream nombre_del_objeto, indicando que es de lectura y escritura con los manipuladores ios::in | ios::out | ios::app. Al crear el objeto, si el archivo fsico no existe se crea fsicamente en blanco, si ya existe lo abre para lectura y escritura. Ejemplo: fstream archivo(nombre_archivo.txt, ios::in | ios::out | ios::app); Para posicionarse en una parte del archivo se usa la funcin miembro seekg Ejemplo: // se posiciona exactamente al final del archivo

archivo.seekg(0, ios::end); //se posiciona 10 caracteres despues del inicio archivo.seekg(10, ios::beg);
El siguiente programa de ejemplo ilustra la entrada y salida en un solo archivo, implementando una bitcora bsica, la idea principal es ir agregando texto en un archivo existente, para llevar un control de las actividades realizadas.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

201

Listado
// bitacora.cpp // abre un archivo para E/S y agrega texto al final del mismo #include <iostream> #include <fstream> #include <cstdlib> using namespace std; int main() { char szTexto[256]; fstream esArchivo("bitacora.txt", ios::in | ios::out | if (esArchivo.fail()) { cout << "Error al abrir archivo! Abortando"; exit(1); } cout << "Texto? "; cin.getline(szTexto, 255); esArchivo.seekg(0, ios::end); esArchivo << szTexto << "\n"; esArchivo.close(); return 0; } Salida Texto? Punteros, referencias y arreglos ios::app);

Nota, Listado del archivo bitacora.txt: Fundamentos del lenguaje subprogramas Punteros, referencias y arreglos

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

202

fstream esArchivo("bitacora.txt", ios::in | ios::out | ios::app);


Se crea el objeto esArchivo, y se abre de entrada y salida con ios::in y ios::out respectivamente, se agrega el manipulador ios::app, para que en caso de que no exista el archivo ste sea creado.

cin.getline(szTexto, 255); getline(), lee toda una lnea del flujo de entrada, con un mximo de 255 caracteres esArchivo.seekg(0, ios::end); Al abrir un archivo para lectura, el indicador de lectura del flujo de entrada se posiciona al inicio del archivo. Como lo que se quiere es agregar texto al final del archivo se usa el seekg(), para mover el indicador al final del archivo. De no hacer esto, cualquier texto agregado al archivo sobrescribe el existente. esArchivo << szTexto << "\n"; Ya que esArchivo es un flujo de datos y fstream se deriva de basic_stream, se asigna la cadena con el operador <<, tal y como se hace con el objeto cout.

7.4 Realizar entrada y salida binaria


Archivos binarios Los archivos binarios son archivos no formateados; se utilizan para manejar los datos byte por byte. Se usa el manipulador ios::binary al abrir el archivo y no se usan los operadores <<, >>.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

203

El siguiente ejemplo es la versin dos de la bitcora, usando estructuras para incluir el porciento terminado de la tarea a grabar en la bitcora, adems cuenta con un men para con las opciones de mostrar el contenido del archivo y agregar nuevos datos. Listado // bitacorax.cpp // agrega texto al final de un archivo #include <iostream> #include <fstream> #include <string> #include <cstdlib> using namespace std; const int LON = 80; struct BitacoraX { int iPorcientoTerminado; char szTexto[LON]; }; int main() { BitacoraX bitacora; int iOpcion, i; fstream esArchivo("bitacorax.dat", ios::out | ios::in | ios_base::app | ios::binary); if (esArchivo.fail()) { cout << "Error al abrir archivo! Abortando"; exit(1); } do { cout << "\n1. Muestra"; cout << "\n2. Agrega"; cout << "\n3. Termina"; cout << "\nOpcion? "; cin >> iOpcion; cin.ignore(); switch (iOpcion) {

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

204

case 1: cout << "Porciento\tTexto\n"; cout << "-------------------------------------------------------" << endl; esArchivo.clear(); esArchivo.seekg(0, ios::beg); esArchivo.read((char *)&bitacora, sizeof(struct BitacoraX)); while (!esArchivo.eof()){ cout << bitacora.iPorcientoTerminado << "\t\t" << bitacora.szTexto << endl; esArchivo.read((char *)&bitacora, sizeof(BitacoraX)); } break; case 2: cout << "\nTexto ? "; cin.getline(bitacora.szTexto, LON-1); cout << "Porciento terminado? "; cin >> bitacora.iPorcientoTerminado; esArchivo.clear(); esArchivo.seekg(0, ios::end); esArchivo.write((const char *)&bitacora, sizeof(BitacoraX)); esArchivo.flush(); break; case 3: break; default: cout << "Opcion no implementada"; } } while (iOpcion != 3); esArchivo.close(); return 0; }

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

205

Salida
1. Muestra 2. Agrega 3. Termina Opcion? 1 Porciento 100 100 70 1. Muestra 2. Agrega 3. Termina Opcion? 2 Texto ? Archivos y estructuras Porciento terminado? 60 1. Muestra 2. Agrega 3. Termina Opcion? 3 Texto Instrucciones basicas control de flujo arreglos

-------------------------------------------------------------

El programa incluye un ciclo donde se presenta un men para seleccionar si se quiere mostrar todos los elementos del archivo, agregar un elemento o terminar el ciclo y por consiguiente cerrar el archivo y terminar la ejecucin del programa. La opcin ingresada se compara en un switch, y en caso de ser la opcin 1, se ejecuta el case 1: lneas de encabezado. y despliega unas

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

206

esArchivo.clear(); Al abrir el archivo, su indicador se encuentra en el inicio del mismo pero al recorrerlo en modo de lectura una vez, se prende la bandera de eof y se queda as. clear(), borra la bandera puesta al alcanzar el fin de archivo -eof- para recorrerlo desde el inicio tantas veces como el usuario as lo desee. esArchivo.seekg(0, ios::beg); seekg(), posiciona el indicador de archivo al inicio, para recorrerlo mientras no sea fin de archivo. esArchivo.read((char *)&bitacora, sizeof(struct BitacoraX)); El mtodo read(), recibe dos parmetros: el primero (char *)&bitcora es el buffer donde se almacenan los datos obtenidos del archivo y el segundo parmetro sizeof(BitacoraX) indica el tamao del buffer; en este caso se invoca la funcin sizeof() la cual regresa el tamao en bytes del tipo de dato recibido como parmetro (en este ejemplo la estructura BitacoraX"). esArchivo.seekg(0, ios::end); seekg(), posiciona el indicador de archivo al final, para agregar datos. esArchivo.write((const char *)&bitacora, sizeof(struct BitacoraX)); El mtodo write(), recibe dos parmetros: el primero (const char *)&bitcora es el buffer donde estn almacenados los datos obtenidos que se van a grabar al archivo y el segundo parmetro sizeof(BitacoraX) indica el
(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes 207

tamao del buffer; en este caso se invoca la funcin sizeof() la cual regresa el tamao en bytes del tipo de dato recibido como parmetro (en este ejemplo la estructura BitcoraX). esArchivo.flush(); flush(), este mtodo graba el flujo del archivo al dispositivo de almacenamiento fsico, esto es para actualizar el contenido del archivo.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

208

Ejercicio Realice un programa donde utilice archivos binarios, que grabe y recupere la siguiente estructura: struct SArticulo { int clave; char descripcion[40]; float precio; };

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

209

Bibliografa

[Stroustrup 1997] Bjarne Stroustrup: The C++ Programming Language Third Edition AddisonWesley 1997 [Stroustrup 1993] Bjarne Stroustrup: El lenguaje de programacin C++ Segunda Edicin Addison-Wesley/Diaz de Santos 1993 [Hernandez 2002] Enrique Hernndez Orallo, Jose Hernndez Orallo y Ma. Carmen Juan Lizandra: C++ Estndar Parainfo Thomson Learning 2002 [Eckel 1993] Bruce Eckel: C++ Inside & Out Osborne McGraw-Hill 1993 [Ellis 1994] Margaret A. Ellis y Bjarne Stroustrup: C++ Manual de referencia con anotaciones Addison-Wesley/Diaz de Santos 1994 [Eckel 2000] Bruce Eckel: Thinking in C++ 2nd ed. volume 1 http://www.BruceEckel.com 2000 [Deitel 1995] H.M. Deitel y P. J. Deitel: Como programar en C/C++ segunda edicin Pearson / Prentice Hall 1995 [Visual C++ 2008 Express Edition] Microsoft Corporation: Ayuda Visual C++ 2008 Express Edition Microsoft Corporation [Builder C++ 5.0] Borland, Inprise Corporation: Ayuda C++ Builder 5.0 Borland, Inprise Corporation [Kernighan 1991] Brian W. Kernighan y Dennis M. Ritchie: El lenguaje de programacin C

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

209

segunda edicin Prentice Hall 1991 [Schildt 1990] Herlbert Schildt: C The Complete Reference second edition Osborne McGrawHill 1990 [Rodriguez 2006] Rogelio Cesar Rodriguez Cervantes Gua para el aprendizaje sistemtico del lenguaje de programacin C++, Proyecto utilitario para presentar examen profesional de conocimientos para la Maestra en tecnologa Informtica en la Universidad Autnoma de Tamaulipas, Mxico.

(c) copyright 2008-2012 Rogelio Cesar Rodriguez Cervantes

210

Вам также может понравиться