Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Unidad I
Unidad I
1.1 Introduccin a C++ 1.2 Estructuras de Datos y Algoritmos en C++ 1.3 Programacin Bsica en C++ 1.4 Administracin de la Memoria 1.5 Mecanismos para la Reutilizacin y Abstraccin del Cdigo
Ago-Dic 2010
Ago-Dic 2010
Historia
Ago-Dic 2010
Principales Caractersticas
C++ es fuertemente tipeado. Cada objeto debe pertenecer a cierto tipo y las operaciones como evaluaciones o comparaciones slo estn permitidas entre objetos del mismo tipo. C++ tiene el concepto de clase, un tipo de registro que combina los miembros de los datos y las funciones que operan sobre los datos. C++ soporta tipos parametrizados o plantillas. Las plantillas hacen posible definir una clase de vector sencillo, que trabaja para datos tipo Booleanos, carcter, enteros, reales, etc. La ventaja real de las plantillas de C++ esta en que su uso no le prohbe al compilador desarrollar la revisin de los tipos estticos o en tiempo de compilacin. C++ soporta herencia, un mecanismo que hace posible construir nuevas clases (llamadas clases derivadas) arriba de una clase existente (llamada la clase base) sin tener que reiterar el diseo de la clase base para cada clase nueva. C++ soporta polimorfismo. sto se logra a travs del uso de funciones virtuales y apuntadores. Junto con la herencia, esto convierte a C++ en un lenguaje orientado a objetos muy completo. C++ viene con dos bibliotecas conocidas como la Biblioteca Estndar y la Biblioteca de Plantillas Estndar (STL), las cuales extienden la capacidad del lenguaje base. La Biblioteca Estndar provee todas las antiguas bibliotecas de C, as como nuevas facilidades de entrada y salida. STL provee una biblioteca de tipo contenedor (tipos que mantienen o "contienen" colecciones de objetos) as como un conjunto de algoritmos asociados (que son algoritmos de propsito general para estructuras comunes de datos). STL complementa los tipos intrnsecos de C++ con vectores, listas enlazadas y otros tipos. C++ tiene una base muy grande de usuarios. Alrededor del mundo, compaas pblicas y privadas, agencias de gobierno, academias y otros usuarios utilizan C++ en todo tipo de formas y aplicaciones. Un beneficio de contar con esta gran base de usuarios es la amplia disponibilidad de diferentes herramientas, bibliotecas y tutoriales, todos relacionados a algn aspecto del lenguaje.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 6
Hello World!
#include <iostream> #include <cstdlib> using namespace std; Listado 1 int main(int argc, char* argv[ ]) { // Say hello. cout << "Hello World!" << endl; /* indicate normal termination */ return EXIT_SUCCESS; }
Ago-Dic 2010
Los programadores de C++ deben realizar cinco pasos para producir una copia ejecutable de un programa:
1. 2. 3. 4.
5.
Editar
El primer paso involucrado en llevar un programa de la fuente a la ejecucin es la creacin de un archivo que contenga el cdigo fuente. El programa que se usa para crear un cdigo fuente es llamado editor. Los editores que los programadores usan, varan de simples y genricos editores de texto (como el Notepad de Windows o el vi de UNIX) a editores sofisticados que tpicamente vienen como parte de los Ambientes de Desarrollo Integrados (ADI's). Estos sofisticados editores son tan poderosos debido a que brindan funcionalidad a travs de la creacin y mantenimiento del cdigo fuente. La sintaxis en colores es un ejemplo de la funcionalidad que estos editores ofrecen.
Ago-Dic 2010
Preproceso
El preprocesamiento involucra la modificacin de los archivos del cdigo fuente antes de la compilacin. Las primeras dos lneas del Listado 1 contienen comandos llamados directivas al preprocesador, las cuales informan al preprocesador que desarrolle alguna accin. Estas lneas indican al preprocesador que incluya el contenido de los archivos dentro del cdigo fuente del programa. El preprocesamiento tambin involucra la sustitucin de textos de macros.
Compilar
El preprocesamiento usualmente es desarrollado de manera automtica justo antes de la etapa de compilacin. La compilacin es un proceso complejo que convierte el cdigo fuente preprocesado en un cdigo objeto. Parte del proceso de compilacin involucra la verificacin de que la sintaxis del cdigo fuente sea vlida. Cuando un programa es compilado (especialmente la primera vez), se tienen errores de sintaxis. Esto es conocido como un "error de compilacin". Cuando nos enfrentamos con un error de compilacin, el programador debe regresar al primer paso de este proceso y editar el cdigo fuente para eliminar el error. La herramienta de software usada para compilar el cdigo fuente es conocida como compilador. Un ejemplo de un compilador de C++ es el GNU o GCC. El GNU compila muchos lenguajes de programacin diferentes, uno de los cuales es C++. El GCC es software gratuito.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 11
Encadenar
El proceso de encadenado es una etapa que normalmente se realiza por la misma herramienta que compila un programa e involucra la combinacin del cdigo objeto producido por el compilador con otro cdigo de biblioteca precompilado. El resultado de esta operacin es un archivo ejecutable. El archivo ejecutable es una imagen que contiene el cdigo objeto del programa compilado y encadenado, grabado en un dispositivo de almacenamiento permanente (el disco duro).
Ejecutar
Despus de que el cdigo fuente del programa ha sido editado, preprocesado, compilado y encadenado en un archivo ejecutable, el programa esta listo para ser ejecutado. Los errores que se detecten en este punto son conocidos como "errores de ejecucin" y normalmente son ms difciles de corregir que los errores de compilacin, debido a que involucran problemas en la lgica del programa.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 13
Muy a menudo, las etapas de preprocesamiento, compilacin y encadenado son agrupadas informalmente y conocidas todas juntas como "compilacin". Es fcil ver esto por que las herramientas que los programadores utilizan desarrollan estas tareas juntas. Por ejemplo, al usar GCC, podemos preprocesar, compilar y encadenar en una misma etapa. La siguiente lnea de comando asume que el cdigo fuente es llamado hello.cpp. $ g++ hello.cpp Como resultado de la ejecucin del comando anterior, el archivo del cdigo fuente hello.cpp ser preprocesado, despus compilado y por ltimo encadenado para producir un archivo ejecutable llamado a.exe. El nombre default del archivo a.exe puede ser reemplazado usando la opcin del compilador -o. $ g++ hello.cpp -o hello.exe
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 14
Las opciones adicionales (-ansi y-pedantic) le informan al compilador que este deber compilar solamente programas que estn escritos en ANSI C++ y que deber emitir mensajes de advertencia cuando encuentre cdigo que viole el estndar de la ANSI. El uso de estas opciones ayuda a localizar y prevenir ciertos tipos de errores. $ g++ -ansi -pedantic hello.cpp -o hello.exe Una vez que el programa ha sido compilado y el archivo ejecutable ha sido generado, el programa puede ser ejecutado. Desde la lnea de comandos, podemos utilizar la siguiente instruccin: $ ./hello.exe El punto y la diagonal que preceden al nombre del archivo no son necesarios, son instrucciones que le indican al sistema operativo que busque al archivo hello.exe en el directorio actual. La siguiente pantalla muestra el resultado de la compilacin y ejecucin del programa.
Ago-Dic 2010
15
Ago-Dic 2010
16
Compilador:
Ago-Dic 2010
17
Ago-Dic 2010
18
Estructuras de Datos
En casi cualquier aspecto del mundo moderno actual, encontramos informacin en todas formas y tamaos. La cantidad de informacin que encontramos es algunas veces tan grande, que sin un mtodo efectivo de almacenaje y representacin, sta se vuelve inservible. (libros guardados en la biblioteca local, o una fila mientras espera comprar boletos en un cine). Una estructura de datos, en el trmino ms simple, es una representacin estructurada de informacin. Tanto el sistema usado para almacenar libros en la biblioteca y la fila de gente en el cine son ejemplos reales de estructuras de datos. Considerando un contexto ms amplio, las estructuras de datos tpicamente representan o almacenan datos para facilitar la solucin de algunos problemas
Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
Ago-Dic 2010
19
En el ejemplo de la biblioteca, el problema que la estructura de datos ayuda a resolver es la localizacin de un libro especfico. En el cine, la gente espera en una fila por lo que es ms fcil determinar quin tiene el siguiente turno. Una estructura de datos puede estar compuesta de piezas simples de datos. Considera tu direccin como una estructura de datos. Existen muchos componentes en esta estructura de datos, todos los cuales son piezas simples de datos. Las estructuras de datos tambin pueden ser complejas, incluso pueden contener otras estructuras de datos. Por ejemplo, una biblioteca contiene muchos estantes, los cuales a su vez contienen muchos libros. Sobre la repisa de uno de estos estantes podra estar una caja de cartn, la cual a su vez contiene unos cuantos libros. En este ejemplo, los estantes es una estructura de datos compuesta de libros y cajas de libros. Las cajas tambin son estructuras de datos, ya que tambin almacenan libros. Tenemos una estructura de datos (estantes) que esta compuesta de otra estructura de datos (una caja). Ambas estructuras de datos proveen un medio para almacenar informacin (los libros) para ayudar a resolver algunos problemas (encontrar un libro especfico).
Ago-Dic 2010
20
Un archivero que contiene carpetas es otro buen ejemplo de como las estructuras de datos pueden componerse de otras estructuras de datos. El archivero es una estructura de datos completa. El archivero esta compuesta de cajones, los cuales contienen carpetas, que a su vez contienen archivos.
Ago-Dic 2010
21
Algoritmos
Adems de tener una estructura de datos que representa informacin, se requiere de algunas secuencias de acciones o serie de pasos, para resolver un problema. La serie de pasos que usa y manipula una estructura de datos para solucionar un problema es llamada algoritmo.
Ago-Dic 2010
22
La estructura de datos:
Una fila de gente.
El algoritmo involucra:
Eliminar a una persona del inicio de la fila (hasta que la fila est vaca) cuando el cajero se desocupa.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 23
Algoritmo:
1. 2.
3. 4.
Esperar a que el cajero est disponible. Eliminar al cliente que est al inicio de la fila. Dejar que el cajero ayude al cliente eliminado. Ir al paso 1.
Ago-Dic 2010
24
Ago-Dic 2010
26
Tipos de Datos
C++ clasifica los objetos de datos en diferentes tipos. Los diferentes tipos de datos:
Describen las operaciones fundamentales que el lenguaje desempea sobre los datos, Describen el rango de valores que los tipos de datos aceptan.
El lenguaje verifica y asegura que un programador asigne solamente valores apropiados al objeto de datos:
Debido a que los diferentes tipos de datos permiten guardar valores diferentes, Si un programador asigna un valor inapropiado, ocurrir un error,
Ejemplo: un nmero que es muy grande o muy pequeo, para un objeto de datos.
Este mecanismo conocido como revisin de tipos hace que C++ sea considerado un lenguaje fuertemente tipeado
Es muy estricto al revisar los tipos de datos y sus valores correspondientes. Esto es bueno para el programador de C++, ya que los lenguajes altamente tipeados pueden detectar errores que otros lenguajes no detectan.
Ago-Dic 2010
27
Java
Boolean
Char Int Short long float double
Ago-Dic 2010
28
Tipos de Datos
El espacio requerido para almacenar variables difiere entre los lenguajes. En C++, los requerimientos de espacio de almacenamiento, son dejados a discrecin del compilador. A diferencia de Java, estos requerimientos no son especficamente establecidos por el estndar del lenguaje.
Por lo tanto, sobre una plataforma de C++ las variables int pueden ocupar dos bytes de longitud, mientras que en otra pueden ocupar cuatro bytes. En Java, una variable de tipo int necesariamente requiere cuatro bytes de memoria. Usualmente el tamao en bytes de una variable no es importante, a menos de que este defina el rango de valores que la variable puede aceptar.
A medida que aumenta el nmero de bytes que una variable necesita para almacenar sus datos, el rango de valores permitido por la variable tambin aumenta.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 29
Tipos de Datos
El siguiente programa usa el operador sizeof de C++ para desplegar el tamao, en bytes, de los tipos de datos de la implementacin particular de C++ usada en la compilacin.
#include <cstdlib> #include <iostream> using namespace std; int main(int argc, char* argv[]) { cout << " bool: " << sizeof(bool) << endl; cout << " char: " << sizeof(char) << endl; cout << " short: " << sizeof(short) << endl; cout << " int: " << sizeof(int) << endl; cout << " long: " << sizeof(long) << endl; cout << " float: " << sizeof(float) << endl; cout << "double: " << sizeof(double) << endl; return EXIT_SUCCESS; }
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 30
C++ contiene un mecanismo para crear variables de "solo-lectura (o "variables constantes" o solo "constantes): usa la palabra reservada const: indica que la variable que ha sido declarada no puede ser modificada despus de que sta haya sido inicializada.
Ago-Dic 2010
31
const int BOILING_POINT = 100; const int FREEZING_POINT = 0; const float PI = 3.14159;
Listado 2 Variables
Los nombres de las variables constantes aparecen en maysculas, aunque esto no es necesario, pero es un estndar que los programadores profesionales de C++ tienden a seguir. El nombrar constantes en maysculas permite a los programadores reconocer y recordar fcilmente que el identificador es una variable constante.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 32
En C++ el tipo de dato cadena de caracteres (string), provee la abstraccin necesaria para permitir que los programadores trabajen con cadenas de caracteres. El tipo cadena de caracteres no est disponible en todos los programas:
Si un programa de C++ requiere el tipo cadena de caracteres, el programador de C++ deber referirse a la biblioteca que define este tipo.
Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
Ago-Dic 2010
33
int main(int argc, char* argv[]) { string s1 = "first"; // Initialization string s2; s1 += " string"; // Concatenation s2 = s1; // Assignment cout << s1 << endl; // Stream output cout << s1.length() << endl; // Length return EXIT_SUCCESS; }
Ago-Dic 2010
34
Arreglos
C++ provee el soporte bsico para una secuencia de datos homogneos a travs de los arreglos. El siguiente listado muestra la declaracin de un arreglo tipo int de tamao diez en C++.
// declare and create an array of integers int cpp_array[10]; Listado 5 Un arreglo en C++
Ago-Dic 2010
35
#include <iostream> #include <cstdlib> using namespace std; int main(int argc, char* argv[]) {
int arr[25];
for (int i = 0; i < 25; i++) { arr[i] = i; } cout << "The first element equals: " << arr[0] << endl; cout << "The second element equals: " << arr[1] << endl; cout << "The last element equals: " << arr[24] << endl; return EXIT_SUCCESS;
Ago-Dic 2010
36
Un peligro inherente que existe al hacer arreglos en C++ es la falta de la verificacin de los lmites del arreglo. En C++, si tenemos un arreglo de diez elementos, podemos intentar acceder las posiciones 12, 20 100 del arreglo. Dependiendo de unas cuantas cosas, el programa puede o no "tronar" como un resultado de querer acceder elementos fuera de los lmites del arreglo. Sin embargo, podemos asegurar que los datos que obtenemos de un acceso fuera de los lmites podran no ser significativos. El siguiente listado muestra un acceso fuera de los lmites en C++.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 37
38
Vectores
El tipo de dato vector provee una alternativa mucho ms segura a un arreglo bsico en C++. En C++, como en Java, los vectores existen como un arreglo con mltiples caractersticas.
Por ejemplo, a diferencia de un arreglo en C++, un vector tiene una funcin que regresa el tamao del vector. Los vectores tambin ofrecen soporte en la revisin de lmites, y a diferencia de los arreglos, automticamente aumentan en tamao cuando se requiere. La pgina 2.2.2 Cmo Usar el Contenedor vector de STL contiene una discusin completa de los datos tipo vector.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
39
C++ da la posibilidad a los programadores de crear nombres adicionales para los tipos de datos existentes. Para crear otro nombre se utiliza la palabra clave typedef con la siguiente sintaxis.
#include <iostream> #include <cstdlib> using namespace std; typedef int my_int; typedef my_int* my_int_ptr; int main(int argc, char* argv[]) { my_int i = 10; my_int_ptr ptr = &i; cout << *ptr << endl; return EXIT_SUCCESS; }
Utilizando nombres de tipos de datos creados con typedef les permite a los programadores encapsular su eleccin de tipos de datos. Esta es una buena prctica de programacin, debido a que, si es necesario, un programador puede fcilmente cambiar todos los usos de un tipo de dato en particular simplemente cambiando la definicin del typedef. Otros beneficios adicionales de la utilizacin de typedef sern examinados en 1.5.3 Plantillas (Templates).
1.3.2 Clases
Sintaxis Bsica Constructores El Destructor Declaracin vs. Definicin
Ago-Dic 2010
43
Sintaxis Bsica
double balance() { return sum;} void deposit(double amount) {sum += amount;} void withdraw(double amount) {sum -= amount;} string getName() { return name;}
}; Listado 2 Clase BankAccount en C++
Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
Ago-Dic 2010
44
Constructores
Los constructores son los mtodos de una clase que definen que acciones tomar al crear un objeto. Una clase en C++ puede tener mltiples constructores:
Esto permite que exista variacin en la instancia de los objetos, debido a que pueden existir nmeros y tipos de parmetros diferentes en cada constructor.
El siguiente listado es una versin modificada de la clase BankAccount de C++. Esta versin modificada incluye un constructor adicional.
class BankAccount { private: double sum; string name; public: BankAccount(string nm) : name(nm), sum(0) {} BankAccount(string nm, double bal) : name(nm), sum(bal) {} double balance() { return sum;} void deposit(double amount) {sum += amount;} void withdraw(double amount) {sum -= amount;} string getName() { return name;} }; Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 45
Los programadores pueden declarar e instanciar objetos en C++ usando una sintaxis idntica a la declaracin de los tipos fundamentales de datos. El listado 4 muestra la instanciacin de la clase BankAccount.
BankAccount account1("checking"); BankAccount account2("savings", 200); account2.withdraw(100); account1.deposit(100); Listado 4 Instanciacin de Objetos
Ago-Dic 2010
46
El Destructor
Un destructor es una funcin miembro especial de una clase de C++, llamada cuando termina el ciclo de vida de un objeto. Al igual que un constructor copy (copy constructor), slo un puede existir un destructor para una clase. Debido a que se ejecutan cuando termina el ciclo de vida de un objeto, los destructores por lo general definen acciones necesarias para liberar recursos que un objeto puede estar usando. Por ejemplo, considera un objeto que abre una conexin a una base de datos. Cuando el ciclo de vida del objeto termina, el destructor puede cerrar esa conexin a la base de datos. Examinaremos usos ms importantes de destructores en la seccin 1.4.3 Administracin de la Memoria Dinmica. Por lo pronto, podemos revisar un listado para ver como se ve la definicin de un destructor en C++.
Listado 5 El destructor
~BankAccount() { if (balance() < 0) { cout << "Warning: negative balance!" << endl; } }
Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
Ago-Dic 2010
47
En esta discusin sobre la especificacin de clases en C++, el trmino "definicin" ha sido usado con respecto a las funciones.
Cuando "definimos" una funcin, dictamos el comportamiento de la funcin a travs del cdigo que existe dentro de los {}.
48
#include <iostream> #include <cstdlib> using namespace std; // function declaration double average(int, int); int main(int argc, char* argv[]) { cout << average(10, 2) << endl; return EXIT_SUCCESS; } // function definition double average(int total, int count) { return (total / count); }
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 49
Ago-Dic 2010
50
Las reglas relacionadas con la especificacin de la clase en C++ ofrecen cierta flexibilidad en la colocacin de las definiciones de la funcin miembro. Una clase en C++ puede incluir todas las definiciones de sus funciones miembro dentro de la definicin de clase. De manera alternativa, las definiciones para una o ms funciones de la clase miembro pueden aparecer fuera de la definicin de clase, siempre y cuando se incluya las declaraciones dentro de la definicin de clase. Los programadores deben calificar completamente los nombres de las funciones de la clase miembro que aparecen fuera de la definicin de clase. Para calificar un nombre completamente, al nombre de la funcin se le debe aadir (prepended) previamente el nombre de la clase, seguido por el operador de resolucin de visibilidad (::).
class BankAccount {
public: BankAccount(string nm) : name(nm), sum(0) {} BankAccount(string nm, double bal) : name(nm), sum(bal) {}
double BankAccount::balance() {
return sum;
} void BankAccount::deposit(double amount) { sum += amount; } void BankAccount::withdraw(double amount) {
sum -= amount;
} string BankAccount::getName() { return name; }
Ago-Dic 2010
52
Las definiciones de funcin de la clase miembro tambin pueden aparecer todas juntas en otro archivo diferente al de la definicin de clase. Cuando un programador especifica una clase de esta forma, puede compilar de forma independiente el archivo que contiene las declaraciones de la funcin de la clase miembro. El archivo que contiene las definiciones de la funcin de la clase miembro es conocido como un archivo de implantacin. El archivo de definicin de clase (o archivo de cabecera o encabezado) se convierte en la interfaz que comparte el cdigo precompilado.
#include <string> #include <cstdlib> #include <iostream> #ifndef _BANKACCOUNT_H #define _BANKACCOUNT_H using namespace std;
#include "bankaccount.h" double BankAccount::balance() { return sum; } void BankAccount::deposit(double amount) { sum += amount; } void BankAccount::withdraw(double amount) { sum -= amount; } string BankAccount::getName() { return name; }
class BankAccount {
private: double sum; string name;
Listado 9 bankaccount.cpp La directiva del preprocesador #include reemplaza la directiva con el contenido del archivo especificado. Las directivas #define, #ifndef y #endif son utilizadas para prevenir que un archivo de definicin no sea incluido en ms de una ocasin. Los usos de las directivas del preprocesador se revisarn en la pgina 1.3.4 El Preprocesador.
public:
BankAccount(string nm) : name(nm), sum(0) {} BankAccount(string nm, double bal) : name(nm), sum(bal) {} double balance(); void deposit(double); void withdraw(double); string getName(); }; #endif
Listado 8 bankaccount.h
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 54
Ago-Dic 2010
55
Flujos (Streams)
La entrada y salida de informacin en C++ se basa en el concepto de un flujo. Un flujo (stream) es una secuencia de bytes que fluyen desde algo hacia algo ms. El proceso de la salida implica el movimiento de bytes, uno a la vez, de un programa a un dispositivo. Este dispositivo poda ser un monitor, impresora, o an un archivo en un disco duro. La entrada de informacin es lo contrario. La entrada de informacin implica el flujo de bytes de un dispositivo (un teclado, un archivo, una conexin de red) hacia el programa.
Ago-Dic 2010
57
Tres flujos especficos estn siempre disponibles a travs del ciclo de vida de cada programa de C++.
stos son los flujos de entrada estndar, salida estndar y error estndar. El flujo de entrada estndar lee datos de la consola, el flujo de la salida estndar escribe datos a la consola, y el flujo de error estndar muestra mensajes de error a la consola.
Los programadores tienen acceso a los flujos estndar a travs de un conjunto de objetos.
Los objetos cin y cout brindan acceso respectivamente a los flujos estndar de entrada y salida. El objeto cerr proporciona acceso al flujo de error estndar.
Ago-Dic 2010
58
Ago-Dic 2010
59
Los programadores de C++ pueden definir cmo las clases que crean interactan con los flujos usando los operadores < < y > >. Esto es conocido como sobrecarga del operador. Las clases del flujo definen la insercin (< <) y la extraccin (> >) para funcionar de una manera especial, para diversos tipos de datos.
Si es utilizada con enteros, nmeros de punto flotante o cadenas de caracteres, estos operadores sacan y dan formato a los datos de la manera apropiada. Podemos tambin definir el comportamiento de estos operadores para las clases que creamos. Esto permite que el cdigo de entrada y salida para las clases definidas por el usuario se asemejen a los cdigos de entrada y salida de los tipos construidos.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 60
class Person { private: string first_name; string last_name; string job; public: Person (string f, string l, string j) : first_name(f), last_name(l), job(j) {} friend ostream& operator<<(ostream& os, Person const& r); }; ostream& operator<<(ostream& os, Person const& r) { os << r.first_name << " " << r.last_name; os << " works as a " << r.job;
return os;
}
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 61
El Listado 3 define la clase Person. Debido a que quisiramos sacar objetos de la clase Person de la misma manera que sacamos enteros o cadenas de caracteres, sobrecargamos el operador < <. Declarar esta funcin como una funcin "amiga" en la lnea 11 permite que la funcin tenga acceso a datos confidenciales de la clase Person. Esto es necesario puesto que la funcin sobrecargada del operador no es un miembro de la clase Person.
Person p("Stan", "Dardeviation", "Math Teacher"); cout << p << endl; Stan Dardeviation works as a Math Teacher
Ago-Dic 2010
62
open input file while( there is input left ) { read next input item process it } close input file
Ago-Dic 2010
63
#include <fstream> #include <iostream> #include <cstdlib> using namespace std; int main(int argc, char* argv[]) { ifstream inf; inf.open("somefile.txt"); if (! inf) { // Check to see if file opened cerr << "Could not open file!" << endl; return EXIT_FAILURE; } int x; // While input remains, read an integer. while (inf >> x) { cout << x << endl; } inf.close(); // Close the input file return EXIT_SUCCESS; }
El objeto usado en la entrada del archivo es del tipo ifstream. Puesto que esta clase no es parte del lenguaje de C++, debemos incluir su biblioteca en nuestro programa. Se declara un objeto del tipo ifstream y se llama la funcin miembro open para abrir un archivo. Es buena prctica de programacin revisar si al intentar abrir un archivo realmente se tiene xito. Uso del operador de extraccin en el condicional del while.: Mientras el intento de extraccin tenga xito, se regresa true (el valor ledo del archivo se asigna a x). Se seala una falla para leer otro entero por un valor de false, lo que termina el while.
Ago-Dic 2010
La salida del archivo se asemeja a su entrada. Necesitamos incluir una referencia a la biblioteca del fstream, Pero utilizamos un objeto ofstream en vez de un objeto ifstream.
ofstream onf; onf.open("output.txt"); if (! onf) { // Check to see if file opened cerr << "Could not open file!" << endl; return EXIT_FAILURE; } for (int i = 1; i <= 10; i++) { onf << "This is line " << i << endl; } onf.close(); // Close the output file Listado 6 Salida del Archivo
Ago-Dic 2010
65
1.3.4 El Preprocesador
Sustitucin de Texto Inclusin de Archivos Sustitucin Macro Compilacin Condicional Ejemplo:Verificacin de Suposiciones
Ago-Dic 2010
66
Sustitucin de Texto
El preprocesador es una herramienta que los programadores de C++ utilizan para manipular el contenido de los archivos del cdigo fuente antes de compilar: el preprocesador realiza la sustitucin y modificacin de texto -> Alto nivel. Un programador interacta con el preprocesador a travs de los comandos llamados directivas del preprocesador. Comenzando con el signo de nmero (#) , las directivas del preprocesador son comandos de una sola lnea que un programador coloca en un archivo del cdigo fuente. La inclusin de archivos, sustitucin macro, y la compilacin condicional son tres caractersticas de alto nivel que el preprocesador brinda al programador. Como los programas de C++ se componen enteramente de texto, un programador debe utilizar el preprocesador para incluir la declaracin de clases o funciones externas. Esto se conoce como inclusin de archivo. Las directivas del preprocesador usadas para definir otras tareas, tales como una sustitucin macro, pueden causar que el preprocesador haga muchas modificaciones en un archivo del cdigo fuente.
Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
Ago-Dic 2010
67
#include <string> #include <cstdlib> #include <iostream> #include <fstream> #include "my_functions.h" #include "my_class.h" #include "..\another_file1.h" #include "directory\sub\another_file2.h" using namespace std; int main(int argc, char* argv[]) {
Listado 1 #include
// Rest of program...
Ago-Dic 2010
68
Sustitucin Macro
#define identifier replacement-text
Ejemplo 1 Forma general de la directiva #define
Podemos utilizar la sustitucin macro para implantar una variable constante.(la sustitucin macro, en el ejemplo anterior, permite que el identificador MAXIMUM funcione como una variable constante. Los programadores de C++ deben utilizar la palabra reservada const en lugar de la sustitucin macro para crear variables constantes.
La palabra reservada const es parte del lenguaje de C++ (y no una caracterstica del preprocesador), Las constantes creadas con ella soportan mejor la revisin de tipos que las constantes creadas usando la sustitucin macro. Las constantes creadas con la sustitucin macro existen en C++ para proveer la compatibilidad con programas de C.
El preprocesador de C++ tambin soporta macros con parmetros. El uso de una macro con parmetros es muy parecido a una funcin normal de C++. El preprocesador sustituye la llamada de la funcin aparente con el texto de reemplazo macro.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 70
Compilacin Condicional
Al utilizar #define, y algunas otras directivas del preprocesador, podemos ordenar al compilador, compilar solamente ciertas secciones de nuestro cdigo fuente. Esto es til en muchas circunstancias, una de las cuales es para insertar el cdigo de depuracin que puede ser habilitado y deshabilitado fcilmente. En seguida, veremos un ejemplo que utiliza las directivas #define, #if, y #endif.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 72
#include <iostream> #include <cstdlib> #define DEBUG using namespace std; int main(int argc, char* argv[]) { #if defined(DEBUG) cerr << "Debugging enabled" << endl; #endif int arr[10]; for (int i = 0; i < 10; i++) { arr[i] = i; #if defined(DEBUG) cerr << "i = " << i << endl;
Ago-Dic 2010
73
La compilacin condicional tambin se utiliza a menudo para prevenir definiciones mltiples de las clases y funciones contenidas en archivos de cabecera (header files). Incluir un archivo de cabecera ms de una vez en un programa puede causar problemas en la redefinicin de la clase y funcin. Podemos prevenir esto con una tcnica que utilice la compilacin condicional.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 74
Verificacin de Suposiciones
double calculate_average(int total, int count) { // avoid divide by zero error if (count != 0) { return total / count; } else { return 0; }
} Listado 7 Verificacin de una suposicin usando una asercin
}
Listado 6 Codificacin defensiva
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 76
En este mdulo, el curso introduce algunos de los conceptos y caractersticas bsicas del lenguaje de programacin C++ relacionadas con la adminis
1.4.1 Apuntadores 1.4.2 Mecanismos de Paso de Parmetros 1.4.3 Administracin de la Memoria Dinmica
1.4.1 Apuntadores
Apuntadores e Indireccin Operaciones Bsicas
Ago-Dic 2010
78
Apuntadores e Indireccin
Un apuntador es una variable que almacena la direccin de la memoria de otra variable. Hemos visto ya en C++ que los tipos de datos dictan el rango y tipo de valores que una variable puede almacenar.
Las variables de los tipos de datos que hemos examinado hasta ahora almacenan valores como por ejemplo enteros, nmeros de punto flotante y cadenas de caracteres (strings).
La variable apuntador es nica ya que salva la direccin de la memoria de otra variable. La direccin de memoria es la localizacin especfica en la memoria principal donde existe una variable durante la ejecucin de un programa. Los programadores usan apuntadores para acceder y manipular indirectamente otras variables.
Este acceso y manipulacin se considera "indirecta" puesto que se logra usando un apuntador en vez de la variable real que est siendo modificada. La "indireccin" permite la creacin de las estructuras de datos complejas y algoritmos poderosos. Por ejemplo, sin apuntadores e indireccin no sera posible crear una estructura de datos de la lista encadenada.
Ago-Dic 2010
79
int *int_ptr; float *float_ptr; char *char_ptr; Listado 1 Declaracin del Apuntador
Ago-Dic 2010
80
Aunque los apuntadores solamente almacenan direcciones de la memoria, la declaracin de una variable apuntador debe especificar un tipo de datos especfico cuya direccin de memoria pueda almacenar el apuntador.
Las variables de diferentes tipos de datos pueden no utilizar necesariamente la misma cantidad de almacenaje en memoria. Para permitir el acceso y la manipulacin indirecta de una variable usando un apuntador, el compilador debe saber el tamao exacto de la variable.
La inicializacin del apuntador tambin requiere algo de sintaxis nueva. No podemos simplemente inicializar un apuntador a una variable no-apuntador porque los apuntadores almacenan las direcciones de memoria y valores no regulares.
Debemos obtener la direccin de memoria de la variable mediante el operador address-of (&), que regresa la direccin de la memoria de donde est almacenada la variable.
Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez
Ago-Dic 2010
81
El listado 2:
declara una variable entera y fija 100 como su valor inicial. declara un apuntador del tipo int, inicializado con la direccin de la variable i.
int i = 100; int *ptr = &i; Listado 2 Inicializacin del Apuntador
ptr "apunta" a i.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 82
Dereferenciar (Dereference)
El acceso indirecto y la manipulacin de variables usando apuntadores se logra usando el operador dereference. Un programador aplica el operador dereference (*) para acceder o modificar el valor de la variable sealada por un apuntador. El Listado 3 demuestra el acceso indirecto y la modificacin de una variable usando un apuntador.
int i = 100; int *ptr = &i; cout << *ptr << endl; // outputs 100 *ptr = 200; // Sets i = 200 cout << i << endl; // outputs 200 Listado 3 Dereferenciacin de apuntadores
Ago-Dic 2010
83
#include <iostream> #include <cstdlib> using namespace std; class Thing { public: int number; Thing() : number(0) {} void method1() { cout << "Method 1" << endl; } void method2() { cout << "Method 2" << endl; } }; int main(int argc, char* argv[]) { // Direct access Thing thing; cout << thing.number << endl; thing.method1(); thing.method2(); // Equivalent indirect access Thing *ptr = &thing; cout << ptr->number << endl; ptr->method1(); ptr->method2(); return EXIT_SUCCESS; }
Se pueden invocar funciones miembro de un objeto a travs de un apuntador. El operador de la flecha (->) primero dereferencia el apuntador y en seguida invoca la funcin miembro nombrada.
Ago-Dic 2010
84
Solamente podemos dereferenciar de forma segura los apuntadores que sealan hacia direcciones vlidas de memoria. Dereferenciar apuntadores que no se han inicializado a direcciones de memoria vlidas causan un error de ejecucin. Una tcnica utilizada para evitar este problema es la inicializacin de variables apuntador al puntero nulo.
El puntero nulo representa un lugar en la memoria que no puede ser dereferenciado. La inicializacin de punteros al puntero nulo, evita que una dereferenciacin accidental pueda causar un error de ejecucin. El apuntador nulo es referenciado usando la macro NULL previamente definida.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 85
int *ptr = NULL; // Initialize to null pointer // ... Some other code ...
Ago-Dic 2010
86
int array[] = {10, 20, 30, 40, 50}; int *ptr = &array[0]; cout << *ptr << endl; ptr++; cout << *ptr << endl; ptr--; cout << *ptr << endl; // outputs 10 // outputs 20
// outputs 10
Ago-Dic 2010
87
La aritmtica del apuntador tiene muchos usos importantes en la programacin en C++. Un uso es el recorrido de arreglos (traversal of arrays).
int data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int *ptr = &data[10]; // points to last element in array do { cout << *ptr << endl; } while (ptr-- != &data[0]);
Ago-Dic 2010
88
Ago-Dic 2010
89
El paso de parmetros por valor es el mecanismo default de paso de parmetros en C++. Cuando un parmetro es pasado por valor a una funcin, se crea y entrega una copia del parmetro a la funcin. Si realizamos un cambio a un parmetro que sea pasado por valor, la variable original permanece sin cambios. El cambio se realiza a una copia de la variable original.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 90
return EXIT_SUCCESS;
}
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 91
#include <iostream> #include <cstdlib> #include <string> #include <cassert> using namespace std; class Person { private: string name; int age; public: Person() : name(""), age(0) {} void set_age(int age) {this->age = age;} int get_age() { return age;} void set_name(string name) {this->name = name;} string get_name() { return name;} }; void increment_age(Person p) { p.set_age(p.get_age() + 1); } int main(int argc, char* argv[]) {
Person person; person.set_name("John Doe"); person.set_age(30); increment_age(person); // age remains unchanged cout << person.get_age() << endl; return EXIT_SUCCESS;
}
Ago-Dic 2010
92
C++ tambin soporta el mecanismo de paso de parmetros por referencia. A diferencia del paso de parmetros por valor, no se hacen copias de las variables que son pasadas por referencia. En su lugar, una funcin llamada recibe una referencia, o alias, al parmetro real provisto por la funcin llamada. Por esta razn, el paso por referencia se utiliza para construir funciones que pueden modificar las variables en la funcin llamada. Incluso cuando una funcin no necesita modificar las variables en la funcin llamada, el paso por referencia es utilizado a veces para evitar el sobreproceso del paso de parmetros por valor. Un uso comn del paso de parmetros por referencia es la creacin de funciones que pueden modificar las variables pasadas a ellas por una funcin llamada.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 93
#include <iostream> #include <cstdlib> using namespace std; void increment(int& x) { x++; // Increment x by 1 } int main(int argc, char* argv[]) {
El parmetro x se declara como parmetro de referencia usando la sintaxis int& x. No confunda este uso del signo "&" con el operador address-of. Aqu el signo "&" seala al compilador que este parmetro debe ser pasado por referencia.
Ago-Dic 2010
94
El
paso de un parmetro por referencia tambin se utiliza como mecanismo para pasar objetos grandes a las funciones. Cuando los objetos son grandes, el paso por valor puede dar lugar a operaciones que consumen demasiado tiempo al sacar copias. El paso por referencia es ms eficiente porque no implica el sacar copias. Incluso cuando una funcin no intenta modificar uno de sus parmetros, se debe usar el paso por referencia cuando el parmetro es un objeto grande. Debemos declarar como constantes los parmetros pasados por referencia que una funcin no debe modificar. Esto es una buena prctica puesto que proporciona proteccin contra modificaciones accidentales.
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 95
A veces es til pasar un apuntador por referencia. Esto se hace cuando una funcin necesita cambiar la posicin almacenada de memoria del apuntador. Es decir se pasa un apuntador a una funcin por referencia cuando la funcin necesita reposicionar el apuntador.
#include <iostream>
#include <cstdlib> using namespace std; void find_first_greater_than(int*& ptr, int threshold) { while (*ptr <= threshold) { ptr++; } } int main(int argc, char* argv[]) { int exam_scores[] = {74, 94, 64, 77, 68, 99, 58, 89, 74, 88, 100, 95, 71, 81, 89, 54, 76, 83, 88, 67}; int* score = &exam_scores[0]; cout << *score << endl; find_first_greater_than(score, 98); cout << *score << endl; return EXIT_SUCCESS; }
Ago-Dic 2010 Algoritmos y Estructura de Datos Dr. Arturo Gonzlez Gutirrez 98
class Person { private: string name; int age; public: Person() : name(""), age(0) {} void set_age(int age) {this->age = age;} int get_age() { return age;} void set_name(string name) {this->name = name;} string get_name() { return name;} char &replace_letter(int i) { return name[i]; } };
Person person; person.set_name("John Doe"); person.set_age(30); person.replace_letter(1) = 'a'; person.replace_letter(2) = 'n'; person.replace_letter(3) = 'e'; cout << person.get_name() << endl;
El paso de parmetros por valor, por default, es un mecanismo usado en C++ para regresar valores de las funciones. Es til, tambin, regresar por referencia para permitir que la funcin llamada modifique algunas variables almacenadas. El Listado 6 muestra cmo regresar por referencia. Este listado aade la funcin replace_letter a la clase Person.
Ago-Dic 2010
99