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

Introduccin

Instrucciones de uso A quien va dirigido este tutorial?


Este tutorial es para aquellas personas que quieren aprender programacin en C++ y no necesariamente tener algn conocimiento previo de otros lenguajes de programacin. Por supuesto, cualquier conocimiento previo de algn lenguaje de programacin o cualquier habilidad general en computadoras puede ser usada para el mejor entendimiento de este tutorial, aunque no es esencial. Si esta familiarizado con el lenguaje C puede tomar las primeras 3 partes de este tutorial como un repaso (desde 1.1 a 3.4), ya que estas principalmente explican la parte C de C++. La parte 4 describe la programacin orientada a objetos. La parte 5 ms que todo describe las nuevas caractersticas introducidas por ANSI-C++ standard.

Estructura de este tutorial


El tutorial esta dividido en 6 partes y cada parte en varias secciones diferentes. Usted puede accesar directamente desde el indice principal o comenzar el tutorial desde cualquier punto y seguir los enlaces al final de cada seccin. Muchas secciones incluyen una pgina adicional con ejemplos especficos que describen el uso del nuevo conocimiento adquirido en ese captulo. Es recomendable leer estos ejemplos y estar en capacidad de entender cada una de las lneas de cdigo que lo constituyen antes de pasar al siguiente captulo. Una buena manera de ganar experiencia con un lenguaje de programacin es mediante la modificacin y adicin de nuevas funcionalidades de su propia cosecha al programa de ejemplo que usted ha entendido completamente. No tenga miedo de modificar los ejemplos provedos en este tutorial. No hay reportes de personas cuyas computadoras se hayan destruido por hacer esto.

Notas de compatibilidad
La aceptacin de El ANSI-C++ standard como un standard internacional es relativamente reciente. Fue publicado en Noviembre de 1997, no obstante el lenguaje C++ existe desde hace mucho tiempo atrs (1980s). Adems hay muchas compiladores que no soportan las nuevas capacidades incluidas en ANSI-C++, especialmente aquellos que se distribuyeron antes de la publicacin del standard.

A lo largo de este tutorial, los conceptos que han sido aadidos ANSI-C++ standard los cuales no estn incluidos en los compiladores ms viejos de C++ estn indicados por el siguiente icono:
<- nuevo en ANSI C++

Tambin, dada la enorme extensin de la que disfruta el lenguaje C (el lenguaje del cual C++ deriva), un icono ser tambin incluido cuando el tema explicado es un concepto cuya implementacin sea claramente diferente en C y C++ o sea exclusiva de C++:
<- diferente implementacin en C y C++

Compiladores
Los ejemplos incluidos en este tutorial son todos programas de consola. Lo que significa que ellos usan texto para comunicarse con el usuario y presentar resultados. Todos los compiladores de C++ soportan la compilacin de programas de consola. Si usted quiere ms informacin sobre como compilar los ejemplos que aparecen en este tutorial, vea el documento Compilacin de Programas de Consola, donde usted encontrara informacin especfica acerca de este tema de varios compiladores de c++ existentes en el mercado.

Seccin 1.1

Estructura de un programa en C++


Probablemente la mejor manera de empezar a aprender un lenguaje de programacin es con un programa. Pues aqu est nuestro primer programa:
// my first program in C++ #include <iostream> using namespace std; int main () { cout << "Hola mundo!"; return 0; }

Hola mundo!

El lado izquierdo presenta el cdigo fuente de nuestro primer programa, al cual podemos llamar, por ejemplo, holamundo.cpp. El lado derecho muestra el resultado del programa una vez compilado y ejecutado. La forma de editar y compilar un programa depende del

compilador que se este usando. Depende, sea que este tenga una interfaz de desarrollo o no en su versin. Consulte la seccin compiladores, o la ayuda incluida en su compilador si tiene dudas acerca de cmo compilar un programa en C++ en la consola. El programa previo es el primer programa que la mayora de los programadores aprendices escriben o codifican, y el resultado impreso es el de la sentencia "Hola mundo!". Este es uno de los programas simples que pueden ser escritos en C++, y adems ya incluye los componentes bsicos que todos los programas en C++ tienen. Vamos a echarles un vistazo uno por uno:
// my first program in C++

Esta es una lnea de comentario. Todas las lneas que comienzan con dos signos slash (//) son consideradas como comentarios y no tienen ningn efecto en el funcionamiento del programa. Estos pueden ser usados por el programador para incluir pequeas explicaciones u observaciones respecto del cdigo en si. En este caso, la lnea es una breve descripcin de lo que hace nuestro programa.
#include <iostream>

Las sentencias que comienzan con el smbolo numeral (#) son directivas del preprocesador. Estas no son lneas de cdigo ejecutable, son indicaciones para el compilador. En este caso la sentencia #include <iostream> le dice al preprocesador del compilador que incluya el archivo de cabecera estndar iostream. Este archivo en especfico, incluye las declaraciones de la biblioteca de entrada y salida estndar bsica en C++, y esta es incluida porque su funcionalidad es usada luego en el programa.
using namespace std;

Esta lnea indica que los nombres de las funciones que sern usadas a continuacin pertenecen al espacio de nombres std o estndares.
int main ()

Esta lnea corresponde al comienzo de la declaracin de la funcin principal main. La funcin main es el punto por el cual comienza la ejecucin de todos los programas en C++. Esto es as independientemente de si la funcin est al final, al principio o en la mitad del cdigo - su contenido siempre ser ejecutado de primero cuando comience la ejecucin del mismo. en adicin, por esa misma razn, es esencial que los programas tengan una funcin main.
main

es seguido de un par de parntesis () porque es una funcin. En C++ todas las funciones estn seguidas por un par de parntesis () los que, opcionalmente , pueden incluir argumentos dentro de ellos. Al contenido de la funcin main le sigue inmediatamente su declaracin formal, la cual est enmarcada entre llaves ({}), as como en nuestro ejemplo.
cout << "Hola mundo!";

Esta instruccin realiza la tarea ms importante en este programa. cout es el flujo de salida estndar en C++ (usualmente la pantalla), y la sentencia completa inserta una secuencia de smbolos (en este caso "Hola mundo!") en el flujo de salida (la pantalla). cout est declarada en el archivo de cabecera iostream, por eso a fin de habilitar su uso este archivo debe ser incluido.

Ntese que cada sentencia termina con un smbolo de punto y coma (;). Este smbolo indica el fin de la instruccin y debe ser incluido al final de cada instruccin en cualquier programa C++ (uno de los errores ms comunes de los programadores de C++ es que olvidan incluir el punto y coma ( ; ) al final de cada instruccin
return 0;

La instruccin de retorno return ocasiona el fin de la ejecucin de la funcin main() y retorna el valor indicado por el cdigo que prosigue a la instruccin, en este caso 0. Esta es la forma ms usual de terminar un programa que no haya encontrado errores durante su ejecucin. Como vera en los siguientes ejemplos, todos los programas C++ terminan con una sentencia similar a esta. Adems usted puede haber notado que no todas las lneas de este programa entran en accin. Hubo lneas contentivas de comentarios (las que comienzan por //), lneas con instrucciones para el preprocesador del compilador (las que comienzan por #), luego hubo lneas que iniciaban la declaracin de una funcin (en este caso la funcin main) y, finalmente lneas con instrucciones (como la llamada a cout <<), estas ltimas estaban todas incluidas dentro del bloque delimitado por las llaves ({}) de la funcin main. El programa ha sido estructurado en varias lneas en aras de hacerlo ms legible, pero no es obligatorio. Por ejemplo, en vez de
int main () { cout << " Hello World "; return 0; }

podramos haber escrito:


int main () { cout << " Hello World "; return 0; }

En tan solo una lnea habramos tenido el mismo resultado. En C ++ la separacin entre instrucciones es con un punto y coma final (;) luego de cada una. La divisin del cdigo en diferentes lneas sirve solo para hacerlo ms entendible y esquemtico para el humano que puede leerlo. Aqu est un programa con algunas instrucciones ms:
// my second program in C++ #include <iostream> using namespace std; int main () { cout << "Hola mundo! ";

Hola mundo! Soy un programa en C++

cout << "Soy un programa en C++"; return 0; }

En este caso usamos el mtodo cout << dos veces en dos instrucciones diferentes. Una vez ms, la separacin en diferentes lneas de cdigo fueron para dar mayor legibilidad al programa, ya que main podra haber sido perfectamente definido como sigue:
int main () { cout << " Hello World! "; cout << " I'm to C++ program "; return 0; }

Tambin somos libres de dividir el cdigo en ms lneas si lo consideramos conveniente:


int main () { cout << "Hola mundo!"; cout << "Soy un programa en C++"; return 0; }

Y el resultado habra sido el mismo que el de los ejemplos anteriores. Las directivas del preprocesador (las que comienzan por #) estn fuera de esta regla ya que ellas no son realmente instrucciones. Ellas son lneas ledas y descartadas por el preprocesador y no producen ningn tipo de cdigo ejecutable. estas deben ser especificadas en su propia lnea y no requiere la inclusin del punto y coma (;) al final.

Comentarios.
Los comentarios son parte del cdigo fuente descartado desde el cdigo al compilador. Estos no hacen nada. Su propsito es solamente permitir al programador insertar notas o descripciones embebidas dentro del cdigo fuente. C++ soporta dos formas de insertar comentarios:
// lnea de comentario /* bloque de comentario */

La primera, la lnea de comentario, descarta todo lo que se encuentra desde los signos de doble slash (//) hasta el final de la misma lnea. El segundo, el bloque de comentario, descarta todo lo que se encuentre entre la aparicin de los smbolos /* y la prxima aparicin de los smbolos */ , con la posibilidad de incluir algunas lneas. vamos a agregar comentario s al segundo programa:

/* my second program in C++ with more comments */ #include <iostream> using namespace std; int main () { cout << "hola mundo! "; // dice hola mundo! cout << "Soy un programa en C++"; // dice soy un programa en C++ return 0; }

Hola mundo! Soy un programa en C++

Si usted incluye dentro del cdigo fuente de sus programas sin la combinacin de smbolos de comentarios //, /* o */,el compilador tomar estos como si fueran instrucciones de C++ y lo ms probable es que esto genere algunos mensajes de error.

Seccin 1.2

Variables. Tipos de Datos. Constantes


La utilidad el programa "Hola Mundo" presentado en la seccin anterior es algo ms que cuestionable. tuvimos que escribir algunas lneas de cdigo, luego compilarlas, y ejecutar el programa resultante para solo obtener una oracin en la pantalla como resultado. Es cierto que hubiera sido ms rpido y simple escribir la oracin de salida por nosotros mismos, pero la programacin no est limitada solo a imprimir texto por pantalla. En aras de ir un poco ms all y hacernos capaces de hacer programas que realicen tareas que realmente ahorren trabajo para nosotros necesitamos presentar el concepto de variable. Vamos a pensar que yo le pida que retenga en su memoria mental el nmero 5 y luego tambin que memorice el nmero 2. Usted tiene solo dos valores guardados en su memoria. Ahora, si yo le pido agregar 1 al primer nmero que le dije, usted debera estar reteniendo el numero 6 (que es 5+1) y el nmero 2 en su memoria. Valores que ahora podemos substraer y obtener 4 como resultado. Todo este proceso que usted ha hecho es similar al que la computadora puede hacer con dos variables. Este mismo proceso puede ser expresado en C++ con el siguiente grupo de instrucciones:
a = 5; b = 2; a = a + 1; result = a - b;

Obviamente es un ejemplo muy simple ya que tenemos que usar solo dos valores enteros pequeos pero considere que su computador puede almacenar millones de numero como estos al mismo tiempo y conducir operaciones matemticas sofisticadas con ellos.

Adems podemos definir una variable como una porcin de memoria que almacena un valor determinado. Cada variable necesita un identificador que las distinga de las dems por ejemplo, en el cdigo previo los identificador de variables eran a, b y result, pero hubiramos podido llamar a estas variables con cualquier nombre que quisiramos inventar, hasta tanto sean identificadores vlidos.

identificadores
Un identificador valido es una secuencia de una o ms letras, dgitos o smbolos de guin de piso ( _ ). La longitud de un identificador es ilimitada aunque para algunos compiladores solo se toman en cuenta los primeros 32 smbolos de un identificador (el resto no es considerado). Ni los espacios ni los signos de puntuacin ni smbolos especiales pueden ser parte de un identificador. Solo letras, dgitos y guin de piso son vlidos. En adicin, los identificadores de variables debern comenzar siempre por una letra. Tambin pueden comenzar con un underline ( _ ), pero esto est usualmente reservado para conexiones externas. En ningn caso pueden comenzar con un dgito. Otra regla que debe considerarse cuando este inventando sus propios identificadores es que ellos no deben coincidir con las palabras reservadas del lenguaje C++ ni las especificadas por su compilador ya que podran confundirse con ellas. Por ejemplo, las siguientes expresiones son consideradas siempre palabras reservadas de acuerdo con ANSI-C++ Standard y adems no pueden ser usadas como identificadores:
asm, auto, bool, break, case, catch, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t

Adicionalmente, representaciones alternativas para algunos operadores no pueden ser usados como identificadores ya que ellas son palabras reservadas bajo ciertas circunstancias:
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq

Su compilador puede incluir tambin algunas palabras reservadas. Por ejemplo, muchos compiladores que generan cdigo de 16 bits (como los compiladores para DOS) incluyen tambin far, huge y near como palabras reservadas. Muy importante: El lenguaje C++ es "case sensitive", esto significa que un identificador escrito en letras maysculas no es equivalente a otros con el mismo nombre pero en letras

minsculas. De este modo, por ejemplo la variable RESULT no es lo mismo que la variable result ni tampoco que la variable Result.

Tipos de Datos
Cuando programamos, guardamos las variables en la memoria de nuestro computador, pero la computadora debe saber que queremos guardar en ellas, ya sea guardar un simple nmero, una letra o un nmero grande, que no van a ocupar el mismo espacio en memoria. La memoria de nuestro ordenador est organizada en bytes. Un byte es la mnima cantidad de memoria que puede ser manejada. Un byte puede almacenar una cantidad relativamente pequea de informacin, usualmente en entero entre 0 y 255 o una simple letra. Pero en adicin, la computadora puede manipular tipos de datos ms complejos que vienen por grupos de algunos bytes, tal como nmeros largos o nmeros con decimales. A continuacin se presenta una lista de los tipos de datos fundamentales existentes en C++, as como el rango de valores que pueden ser representados con cada uno de ellos: TIPOS DE DATO Nombre Bytes* Descripcin char short long 1 2 4 Rango* signed: -128 to 127 letra o entero 8 bits de longitud. unsigned: 0 to 255 signed: -32768 to 32767 entero 16 bits length. unsigned: 0 to 65535 signed:-2147483648 to entero 32 bits length. 2147483647 unsigned: 0 to 4294967295 entero. Su longitud depende tradicionalmente de la arquitectura del sistema y del tamao de las palabras en el mismo, de este modo en MSDOS es de 16 bits de longitud, Ver short, long mientras que en sistemas de 32 bit (como Windows 9x/2000/NT y sistemas que trabajan bajo modo protegido en sistemas x86) es de 32 bits de longitud (4 bytes). nmero punto flotante. 3.4e + / - 38 (7 dgitos) nmero punto flotante de doble 1.7e + / - 308 (15 dgitos) precisin nmero largo punto flotante de 1.2e + / - 4932 (19 dgitos) doble precisin

int

float

double 8 long 10 double

bool

wchar_t 2

Valor Booleano. puede tomar uno de dos valores: true or false NOTA: este es un tipo de dato recientemente aadido por el ANSI-C++ Standard. No todos true o false los compiladores lo soportan. Consulte la seccin bool type de cplusplus.com para informacin de compatibilidad. Smbolo ancho. Esta diseado para almacenar smbolos y/o letras internacionales smbolos anchos almacenados en un set de dos bytes. NOTA: este es un tipo de (wide characters) dato recientemente aadido por el ANSI-C++ Standard. No todos los compiladores lo soportan.

* Los valores de las columnas Bytes and Rango pueden variar segn el sistema. Los valores incluidos aqu son los ms frecuentes y comnmente aceptados y usados por la mayora de los compiladores. En adicin, estos tipos fundamentales de datos, tambin existen los punteros y la especificacin del tipo de parmetro void, que veremos luego.

Declaracin de variables
Para poder usar una variable en C++, primero debemos declararla especificando cul de los tipos de datos presentados arriba queremos que sea. La sintaxis para declarar una nueva variable es escribir el especificador de tipo de dato que queremos (como int, short, float...) seguido por un identificador de variable. Por ejemplo:
int a; float mynumber;

Son declaraciones validas de variables. La primera declara una variable de tipo int con el identificador a. La segunda declara una variable de tipo float con el identificador mynumber. Una vez declaradas, las variables a y mynumber pueden ser usadas dentro del resto de su contexto en el programa. Si necesita declarar algunas variables del mismo tipo y quiere ahorrarse escritura, puede declarar todas estas en la misma lnea separando los identificadores con comas ( , ). Por ejemplo:
int a, b, c;

declara tres variables (a, b y c) de tipo int , y tiene exactamente el mismo significado que si hubiramos escrito:
int a; int b; int c;

El tipo de dato entero int (char, short y long) pueden estar con sigo o sin signo (signed or unsigned) de acuerdo al rango de nmeros que necesitemos representar. De este modo para especificar un tipo de dato entero lo hacemos poniendo la palabra reservada signed o unsigned antes del tipo de dato como tal. por ejemplo:
unsigned short NumberOfSons; signed int MyAccountBalance;

Por defecto, si no especificamos signed o unsigned se asume que el tipo de dato es signed, adems en la segunda declaracin pudimos haber escrito:
int MyAccountBalance;

con exactamente el mismo resultado ya que es el modo mas usual, pocos cdigos incluyen la palabra reservada signed como parte del compendio de tipo de nombres. La nica excepcin de la regla es el tipo char que existe como tal y es considerado de un tipo distinto al signed char y unsigned char. Finalmente, signed y unsigned pueden tambin ser usados como tipos simples, significando lo mismo que signed int y unsigned int respectivamente. Las siguientes dos declaraciones son equivalentes:
unsigned MyBirthYear; unsigned int MyBirthYear;

Para ver las declaraciones de variables en accin en un programa, vamos a presentar el cdigo C++ para el ejemplo de su memoria mental propuesto al inicio de esta seccin:
// operating with variables #include <iostream> using namespace std; int main () { // declaring variables: int a, b; int result; // process: a = 5; b = 2; 4

a = a + 1; result = a - b; // print out the result: cout << result; // terminate the program: return 0; }

No se preocupe si algo en la declaracin de variables luce un tanto extraa para usted. Ver el resto en detalle en la siguientes secciones.

Inicializacin de variables
Cuando declaramos una variable local, su valor es indeterminado por defecto. Pero usted podra querer que una variable almacene un valor en concreto al momento de su declaracin. Para hacer esto, usted tiene que anexar un signo igual seguido por el valor deseado en la declaracin de la variable:
type identifier = initial_value ;

Por ejemplo, si queremos declarar una variable entera int llamada a que contenga el valor 0 al momento en el cual es declarada, podramos escribir:
int a = 0;

Adicionalmente a esta forma de inicializacin de variables (conocida como c-like), C++ ha aadido una nueva manera de inicializar una variable: encerrando el valor inicial entre parntesis ():
type identifier (initial_value) ;

por ejemplo:
int a (0);

Ambas formas son validas y equivalentes en C++.

Contexto de variables
Todas la variables que estn siendo usadas deben estar previamente declaradas. Una diferencia importante entre los lenguajes C y C++, es que en C++ podemos declarar variables en cualquier lugar del cdigo fuente, hasta entre dos sentencias ejecutables, y no slamente al inicio del bloque de instrucciones, como ocurre en C.

De todos modos, es recomendable bajo ciertas circunstancias seguir las indicaciones del lenguaje C cuando declaremos variables, ya que puede ser til durante la depuracin de un programa que tiene agrupadas todas las declaraciones en un mismo sitio. Adems el tradicional modo C-like de declarar variables contempla incluir las declaraciones al comienzo de cada funcin (para variables locales) o directamente en el cuerpo del programa, fuera de cualquier funcin (para variables globales). Variables Globales pueden ser referidas a cualquier lugar del cdigo, dentro de una funcin, siempre y cuando est despus de la declaracin. El contexto de las variables locales est limitado al nivel de cdigo en el cual son declaradas. Si ellas son declaradas al inicio de una funcin (como en main) su contexto es toda la funcin main. En el ejemplo contiguo, esto significa que si otra funcin que exista aparte de la funcin main(), las variables locales declaradas en main no podran ser usadas en otra funcin y viceversa. En C++, el contexto de una variable local est dado por el bloque en el que es declarada (un bloque es un grupo de instrucciones agrupadas dentro de los smbolos "llaves" {}). Si esta es declarada dentro de una funcin su contexto ser el contexto de la funcin, si es declarada dentro de un lazo, su contexto sera solo el lazo, etc... En adicin a los contextos locales y globales existen contextos externos, que hacen que una variable sea visible no solo en el mismo cdigo fuente sino en todos los dems archivos que sern enlazados.

Constantes: Literales.
Una constante es cualquier expresin que tenga un valor arreglado. Estos pueden ser divididos en nmeros Enteros, nmeros Punto-Flotante, Cadenas y smbolos. Nmeros Enteros
1776 707 -273

Estas son constantes numricas que identifican nmeros enteros decimales. Note que para expresar una constante numricas no necesitamos escribir comillas (") ni otro smbolo especial. No hay duda de que es una constante dondequiera que se escriba 1776 en un programa, nos estaremos refiriendo a el valor 1776. En adicin a los nmeros decimales (esos que ya todos nosotros conocemos) C++ permite el uso de constantes literales de nmeros octales (base 8) y nmeros hexadecimales (base 16). Si queremos expresar un nmero octal debemos precederlo con un smbolo 0 (caracter cero). Y para expresar un nmero hexadecimal tenemos que precederlo con los smbolos 0x (cero, x). Por ejemplo, las siguientes constantes literales son todas equivalentes entre si:
75 0113 0x4b // decimal // octal // hexadecimal

Todas representan el mismo numero: 75 (setenta y cinco ) expresado como un nmero base 10, octal y hexdecimal, respectivamente. [ Nota: Puede encontrar mayor informacin sobre representacin hexadecimal y octal en el documento Bases numricas] Nmeros Punto Flotante Estos expresan nmeros con decimales y/o exponentes. Estos pueden incluir un punto decimal, un smbolo e (que expresa "por 10 a la n-esima potencia", donde n es el siguiente valor entero) o ambos.
3.14159 6.02e23 1.6e-19 3.0 // // // // 3.14159 6.02 x 1023 1.6 x 10-19 3.0

estos son cuatro nmeros vlidos con decimales expresados en C++. El primer nmero es PI, el segundo es el numero de Avogadro, el tercero es la carga elctrica de un electrn (un nmero extremadamente pequeo) -todos ellos aproximados- y el ltimo es el nmero 3 expresado como un literal numrico en punto flotante. Caracteres y cadenas Tambin existen constantes no numricas, como:
'z' 'p' "Hola mundo" "Como te va?"

Las primeras dos expresiones representas smbolos simples (solos) y las siguientes dos representan cadenas de varios caracteres. Note que para representar un caracter simple se encierra entre comillas simples (') y para expresar una cadena de ms de un caracter los encerramos entre comillas dobles (").

Cuando escribimos caracteres y cadenas de caracteres de manera constante, es necesario poner las comillas para distinguirlas the posibles identificadores de variables o palabras reservadas. Note esto:
x 'x' x

se refiere a la variable x, mientras que 'x' se refiere al caracter constante 'x'.

Los caracteres constantes y las cadenas constantes tienen ciertas peculiaridades, como los escape codes o caracteres especiales como los llamaremos en adelante, que no pueden ser expresados de otro modo en el cdigo fuente de un programa, como el smbolo de nueva lnea (\n) o tabulado (\t). Todos estos estn precedidos por el smbolo slash invertido(\). aqu tiene una lista de tales smbolos especiales:
\n \r \t \v \b \f \a \' \" \? \\

nueva lnea retorno de carro tabulacin tabulacin vertical backspace alimentacin de pagina alerta (beep) comilla simple (') comilla doble (") interrogacin (?) slash invertido(\)

Por ejemplo:
'\n' '\t' "Left \t Right" "one\ntwo\nthree"

Adicionalmente, usted puede expresar cualquier smbolo por su correspondiente valor numrico en cdigo ASCII escribiendo slash invertido (\) seguido por el cdigo ASCII expresado como un nmero octal (base 8) o hexadecimal (base 16). En el primer caso (octal) el nmero debe seguir inmediatamente el slash invertido (por ejemplo \23 o \40), en el segundo caso (hexacedimal), usted debe poner un smbolo x antes del nmero (por ejemplo \x20 o \x4A). [Consulte el documento ASCII Code para ms informacin acerca de este tipo de simbologa especial].

Las constantes de cadenas de caracteres pueden extenderse de una simple lnea de cdigo si cada lnea de cdigo termina con un slash invertido (\):
"string expressed in \ two lines"

Usted puede tambin econcatenar varias cadenas constantes separndolas por uno o varios blankspaces, tabuladores, nueva lnea o cualquier otro de los caracteres blank vlidos:
"we form" "a single" "string" "of characters"

Constantes definidas como Macros (#define)


Usted puede definir sus propios nombres para constantes que usar completamente sin tener que recurrir a variables, simplemente usando la directiva del preprocesador #define. Este es su formato:
#define identificador valor

Por ejemplo:
#define PI 3.14159265 #define NEWLINE '\n' #define WIDTH 100

Ellos definen tres nuevas constantes. Una vez declarados, usted estar habilitado para usarlos en el resto del cdigo tal y como si fueran cualquier otra constante, por ejemplo:
circle = 2 * PI * r; cout << NEWLINE;

En realidad lo nico que el compilador hace cuando encuentra directivas #define es reemplazar literalmente cualquier ocurrencia de ellos (en el ejemplo previo, PI, NEWLINE o WIDTH) por el cdigo al cual fueron definidos (3.14159265, '\n' y 100, respectivamente). Por esta razn #define constantes consideradas como macro constantes. La directiva #define no es una instruccin de cdigo, es una directiva del preprocesador, adems asume que toda la lnea es la directiva y no requiere un punto y coma (;) al final de la misma. Si usted incluye un smbolo de punto y coma (;) al final, este tambin ser aadido cuando el preprocesador sustituya cualquier ocurrencia de la constante definida dentro del cuerpo del programa.

Constantes declaradas (const)


con el prefijo const usted puede declarar constantes con un tipo especifico exactamente igual a como hara con una variable:

const int width = 100; const char tab = '\t'; const zip = 12440;

En caso de que el tipo no sea especificado (como en el ultimo ejemplo) el compilador asume que es de tipo int.

Seccin 1.3

Operadores
Ya que conocemos de la existencia de variables y constantes podemos empezar a operar con ellas. Para tal propsito, C++ provee a los operadores, los cuales en este lenguaje son un grupo palabras claves o reservadas y signos que no so parte del alfabeto pero estn disponibles en todos los teclados. Es importante conocerlos ya que son las bases del lenguaje C++. Usted no tiene que memorizar todo el contenido de esta pgina, los detalles son dados solo para servir como referencia a posteriori en caso de que los necesite. Asignacin (=). El operador de asignacin sirve para asignar un valor a una variable.
a = 5;

asigna el valor 5 a la variable a. La parte izquierda del operador = es conocida como lvalue (left value) y la parte derecha como rvalue (right value). lvalue debe ser una variable mientras que el lado derecho puede ser tanto una constante como una variable, o el resultado de una operacin o combinacin de ellas. Es necesario enfatizar que la operacin de asignaci siempre toma lugar de derecha a izquierda y nunca a la inversa.
a = b;

asigna a la variable a (lvalue) el valor que contiene la variable b (rvalue) independientemente del valor que tenga almacenado a en ese momento. Considere tambin que solo se esta asignado el valor de b a a y que un cambio posterior de b no afectar el nuevo valor de a. Por ejemplo, si tomamos este cdigo (con la evolucin de los contenidos de las variable en color verde):
int a = b = a = b = a, b; 10; 4; b; 7; // // // // // a:? b:? a:10 b:? a:10 b:4 a:4 b:4 a:4 b:7

nos dara como resultado que el valor contenido en a es 4 y el contenido en b es 7. La modificacin final de b no ha afectado a a, aunque anteriormente habamos declarado que a = b; (regla del right-to-left). Una propiedad que C++ tiene, a diferencia de otros lenguajes de programacin es que la operacin de asignacin puede ser usada como el valor rvalue (o parte de un rvalue) de otra asignacin. Por ejemplo:
a = 2 + (b = 5);

es equivalente a:
b = 5; a = 2 + b;

esto significa: en la primera asigna 5 a la variable b y luego asigna a a el valor 2 ms el resultado de la asignacin previa de b (que es 5), dejando a a con el valor final de 7. De esta manera, la siguientes expresin es solo vlida en C++:
a = b = c = 5;

asigna 5 a las tres variables a, b y c. Operadores aritmticos ( +, -, *, /, % ) Los cinco operadores aritmticos soportados por el lenguaje son: + adicin - substraccin * multiplicacin / divisin % modulo o resto Las operaciones de adicin, substraccin, multiplicacin y divisin no suponen un reto a la comprensin y el entendimiento para usted ya que corresponden literalmente con sus respectivos operadores matemticos. El nico que puede que usted no conozca es el mdulo, especificado con el smbolo de porcentaje (%). El mdulo es la operacin que da como resultado el resto de la divisin entera de dos valores enteros cualesquiera. Por ejemplo, si escribimos a = 11 % 3;, la variable a va a contener 2 como resultado ya que 2 es el resto de la divisin de 11 entre 3. Operadores de asignacin compuesta (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=) Una caracterstica a favor de la asignacin en C++ que contribuye a su fama de lenguaje abreviado o corto cuando escribimos son lo operadores de asignacin compuesta (+=, -=, *= y /= entre otros), los cuales permiten modificar el valor de una variable con uno de los operadores bsicos:

valor += incremento; es equivalente a valor = valor + incremento; a -= 5; es equivalente a a = a - 5; a /= b; es equivalente a a = a / b; price *= units + 1; es equivalente a price = price * (units + 1);

igual para todos las dems operaciones. incremento y decremento. Otro ejemplo de ahorro de escritura del lenguaje cuando se codifica son los operadores de incremento (++) y decremento (--). Ellos incrementan o reducen en 1 el valor actualmente almacenado en una variable. Ellos son equivalentes a +=1 y =1, respectivamente. Por tanto:
a++; a+=1; a=a+1;

son todos equivalentes en su funcionalidad: los tres incrementan en 1 el valor de a. Su existencia se debe a que en el primer compilador de C las tres expresiones previas producan cdigos ejecutables diferentes de acuerdo a cual fuera usado. Hoy d este tipo de optimizacin de cdigo es hecha generalmente de manera automtica por el compilador. Una caracterstica de este operador es que ambos pueden ser usados como prefijo o sufijo. Esto significa que pueden ser escritos antes o despus del identificador de la variable (++a) o despus (a++). Aunque en expresiones simples como a++ o ++a tienen exactamente el mismo significado, en otras operaciones en las cuales el resultado de incrementar o decrementar es evaluado como otra expresin, estas pueden tener una diferencia importante en su significado: En caso de que el operador de incremento sea usado como prefijo (++a) el valor es incrementado antes de que la expresin sea evaluada y adems el valor incrementado es considerado en la expresin; en el caso de que sea usado como sufijo (a++) el valor almacenado en a es incrementado despus de ser evaluado y adems el valor almacenado antes de la operacin de incremento es evaluado en la expresin. Note la diferencia: Ejemplo 1 Ejemplo 2

B=3; B=3; A=++B; A=B++; // A es 4, B es 4 // A es 3, B es 4

En el ejemplo 1, B es incrementada antes que su valor sea copiado a A. Mientras que en el ejemplo 2, el valor de B es copiado a A y B despus es incrementado. Operadores Relacionales ( ==, !=, >, <, >=, <= )

Para evaluar una comparacin entre dos expresiones podemos usar los operadores relacionales. Como esta especificado por el ANSI-C++ standard, el resultado de una operacin relacional es un valor del tipo bool bool que puede ser solo true o false, de acuerdo al resultado de la comparacin. Podramos querer comparar dos expresiones, por ejemplo, saber si ellas son iguales o si una es mayor que la otra. Aqu est una lista de los operadores relacionales que pueden ser usados en C++:
==

Igual != Diferente > Mayor que < Menor que >= Mayor o igual que <= Menor o igual que Aqu tiene algunos ejemplos:
(7 == 5) (5 (3 (6 (5

retornara false. > 4) retornara true. != 2) retornara true. >= 6) retornara true. < 5) retornara false.

por supuesto, en vez de usar solo constantes numricas, podemos usar una expresin vlida, incluyendo variables. Suponga que a=2, b=3 y c=6,
(a == 5)

retornara false. (a*b >= c) retornara true ya que(2*3 >= 6) es tal. (b+4 > a*c) retornara false ya que (3+4 > 2*6) es tal. ((b=2) == a) retornara true. Dese cuenta. El operador = (un signo de igual) no es lo mismo que el operador == (dos signos de igual), el primero es un operador de asignacin asigna el valor del lado derecho de la expresin a la variable de la izquierda) y el otro (==) es un operador relacional de igualdad que compara y dice si ambas expresiones de lado y lado del operador son iguales la una a la otra. Por tanto, en la ltima expresin ((b=2) == a), primero asignamos el valor 2 a b y luego lo comparamos con a, que tambin guarda el valor 2, y as el resultado de la operacin es true. En muchos compiladores anteriores a la publicacin de el ANSI-C++ standard, como es el del lenguaje C, la operacin relacional no retorna un valor del tipo

bool, o sea, true o false, ms bien retornaban un entero int como resultado con valor 0 para representar "false" y un valor diferente de 0 (generalmente 1) para

el

representar "true". Para mas informacin acerca de si su compilador soporta o no el tipo bool, consulte la seccin bool type.de cplusplus.com Operadores lgicos ( !, &&, || ). El operador ! es equivalente a la operacin booleana NOT, este tiene solo un operando, localizado a su derecha, y lo nico que hace es invertir el valor de su operando, hacindolo false si es true y true si es false. Es como decir que devuelve el resultado opuesto de la evaluacin de su operando. Por ejemplo: !(5 == 5) retorna false porque la expresin a su derecha (5 == 5) seria true. !(6 <= 4) retorna true porque(6 <= 4) seria false. !true retorna false. !false retorna true. Los operadores lgicos && y || son usados cuando se evalan dos expresiones para obtener un resultado simple. Ellos corresponden con las operaciones lgicas booleanas AND y OR respectivamente (Y y O). El resultado de ellos depende de la relacin entre sus dos operandos: Primer Segundo resultado resultado Operando Operando a && b a || b a b true true false false true false true false true false false false true true true false

Por ejemplo:
( (5 == 5) && (3 > 6) ) retorna false ( true && false ). ( (5 == 5) || (3 > 6)) retorna true ( true || false ).

Operador condicional ( ? ). El operador condicional ( u operador ternario ) evala una expresin y retorna un valor diferente de acuerdo a la expresin evaluada, dependiendo de si es true o false. Su formato es:
condition ? result1 : result2

si condition es true la expresin retornar result1, si no retornara result2.


7==5 ? 4 : 3

retorna 3 ya que 7 es diferente de 5. 7==5+2 ? 4 : 3 retorna 4 ya que 7 es igual a 5+2.

retorna a, ya que 5 es mayor que 3. a>b ? a : b retorna el mayor entra, a y b. Operadores de manejo de bits ( &, |, ^, ~, <<, >> ). Los operadores de manejo de bits modifican variables considerando los bits que representan el valor que ellos almacenan, esto es, su representacin binaria. op asm Description & AND Y lgico | OR O lgico ^ XOR O lgico exclusivo ~ NOT Complemento a uno (inversin de bits) << SHL Cambio o desplazamiento a la izquierda >> SHR Cambio o desplazamiento a la derecha Para mayor informacin acerca de nmeros binarios y operaciones de bits, consulte Lgica Booleana. Operadores de casting explicitos (moldeo) Los operadores de casting le permiten convertir un dato de un tipo dado a otro. Hay varias formas de hacer esto en C++, el ms popular, compatible con el lenguaje C es preceder a la expresin a ser convertida por el nuevo tipo encerrado entre parntesis ():
int i; float f = 3.14; i = (int) f;

5>3 ? a : b

El cdigo previo convierte el nmero flotante 3.14 a un valor entero (3). Aqu, el operador de moldeo, o casting fue (int). Otra forma de hacer lo mismo en C++ es usando la forma del constructor: precediendo la expresin a ser convertida por el tipo y encerrando la expresin entre parntesis:
i = int ( f );

Ambas formas de casting son vlidas en C++. Y adicionalmente ANSI-C++ aadi nuevos operadores ms especficos para programacin orientada a objetos (Seccin 5.4, class type-casting Avanzado). sizeof() Este operador acepta un parmetro, que puede tanto una variable o un especificados de tipo de dato como tal y retorna el tamao en bytes del tipo u objeto:
a = sizeof (char);

Este retornar 1 a a porque char es de un byte de longitud. El valor retornado por sizeof es una constante, y siempre esta determinado antes de la ejecucin del programa. Otros operadores Ms adelante en el tutorial veremos otros pocos operadores como el que se refiere a los apuntadores o los especficos para la programacin orientada por objetos. Cada uno es tratado en sus respectivas secciones.

Prioridad de los operadores


Cuando hacemos expresiones complejas con varios operandos, podramos tener dudas acerca de cual operando es evaluado primero y cual despus. Por ejemplo, en esta expresin:
a = 5 + 7 % 2

podramos dudar si esta realmente significa:


a = 5 + (7 % 2) a = (5 + 7) % 2

y su resultado 6, o y su resultado 0

La respuesta correcta es la primera de las dos expresiones, con un resultado de 6. Hay un orden establecido con la prioridad de cada operador, y no solo con los aritmticos (aquellos cuya preferencia podra ser conocida ya desde las matemticas) sino para todos los operadores que aparecen en C++. Desde las mayores hasta las menores prioridades, el orden de precedencia es como sigue: Prioridad Operador :: 1 2
() [ ] -> . sizeof ++ -~ !

Descripcin ambito incremento/decremento Complemento a uno (bits) NOT unario Referencia y Dereferencia (punteros) Type casting Unario sin signo Operaciones aritmticas Operaciones aritmticas Desplazamiento de bits Operadores relacionales

Asociatividad Izquierda Izquierda

& * (type) + -

Derecha

4 5 6 7

* / % + << >> < <= > >=

Izquierda Izquierda Izquierda Izquierda

8 9 10 11 12 13

== != & ^ | && || ?: = += -= *= /= %= >>= <<= &= ^= |= ,

Operadores relacionales Operadores con bits Operadores lgicos Condicional Asignacin Coma, Separador

Izquierda Izquierda Izquierda Derecha Derecha Izquierda

Asociatividad define -en el caso en que sean varios operadores de la misma prioridad- cual sera evaluado primero, el ms a la derecha o el ms a la izquierda. Todos estos ordenes de precedencia para los operadores pueden ser manipulados pero para mayor legibilidad se pueden usar parntesis ( y ), como en este ejemplo:
a = 5 + 7 % 2;

puede ser escrito como:


a = 5 + (7 % 2); a = (5 + 7) % 2;

de acuerdo a la operacin que queramos realizar. Y si quiere escribir una expresin complicada y no esta seguro del orden de precedencia, siempre incluya los parntesis. Esto tambin probablemente hara su cdigo ms legible.

Seccin 1.4

Comunicacin a travs de la consola


La consola es la interfaz bsica de las computadoras, normalmente es el conjunto compuesto del teclado y la pantallas. El teclado es generalmente el dispositivo de entrada standard y la pantalla el dispositivo de salida standard. en la biblioteca iostream de C++ , las operaciones de entrada y salida standard para un programa estarn soportadas por dos flujos de datos: cin para entrada y cout para salida. Adicionalmente, cerr y clog estn tambin implementados - estos son dos flujos de salida especialmente diseados para mostrar mensajes de error. Ellos pueden ser redireccionados a la salida estandard o a un archivo de registro. Adems cout (el flujo de salida standard) normalmente est dirigido a la pantalla y cin (el flujo de entrada estandard) normalmente esta asignado al teclado.

Por el manejo de estos dos flujos estar habilitado para interactuar con el usuario en sus programas ya que podr presentar mensajes en la pantalla y recibir su entrada desde el teclado.

Salida (cout)
El flujo cout es usado en conjuncin con el operador sobrecargado << (un par de signo "menor que" ).
cout << "Output sentence"; // imprime la oracin de Salida por pantalla cout << 120; // imprime el numero 120 por pantalla cout << x; // imprime el contenido de la variable x por pantalla

El operador << es conocido como operador de insercin, ya que este inserta la data que le sigue en el flujo que lo precede. En e ejemplo de arriba este inserto la cadena constante "Output sentence", la constante numrica 120 y la variable x en el flujo de salida cout. Note que la primera de las dos sentencias est encerrada entre comillas dobles (") porque es una cadena de caracteres. Cuando queramos usar cadenas constantes debemos encerrarlas entre comillas dobles (") debido a que pueden ser claramente distinguidas como variables. Por ejemplo, estas dos sentencias son muy diferentes:
cout << "Hello"; cout << Hello; pantalla // imprime Hello por pantalla // imprime el contenido de la variable Hello por

El operador de insercin (<<) puede ser usado mas de una vez en la misma sentencia:
cout << "Hello, " << "I am " << "a C++ sentence";

esta ltima sentencia imprimira el mensaje Hello, I am a C++ sentence por pantalla. La utilidad de repetir el operador de insercin (<<) es demostrar que hacer cuando queramos imprimir una combinacin de variables y constantes o ms de una variable:
cout << "Hello, I am " << age << " years old and my zipcode is " << zipcode;

si suponemos que la variable age contiene el numero 24 y la variable zipcode contiene 90064 la salida de la sentencia previa seria:
Hello, I am 24 years old and my zipcode is 90064

es importante notar que cout no agrega una ruptura de lnea despus de su salida a menos que nosotros la indiquemos explcitamente, adems las siguientes sentencias:
cout << "This is a sentence."; cout << "This is another sentence.";

sern impresas por pantalla como sigue:


This is a sentence.This is another sentence.

aunque las hallamos escrito en dos llamadas diferentes del cout. Entonces, en orden de hacer una ruptura de lnea o salto de lnea en la salida debemos ordenarlo explcitamente mediante la insercin del smbolo de nueva lnea, que en C++ puede ser escrito como \n:
cout << "First sentence.\n "; cout << "Second sentence.\nThird sentence.";

produce la siguiente salida:


First sentence. Second sentence. Third sentence.

Adicionalmente, para agregar una nueva lnea, usted tambin puede usar el manipulador endl. Por ejemplo:
cout << "First sentence." << endl; cout << "Second sentence." << endl;

imprimira
First sentence. Second sentence.

El manipulador endl tiene una funcin especial cuando es usado con flujos regulados (buffered streams): estos son vaciados. Pero de cualquier manera cout no es regulado (unbuffered) por defecto. Usted puede usar indistintamente el smbolo especial \n o el manipulador endl para especificar un salto de lnea para cout. Note la diferencia de usos presentadas anteriormente.

Entrada (cin).
El manejo de la entrada standard en C++ es hecha mediante la aplicacin del operador sobrecargado de extraccin (>>) en el flujo cin. Este debe ser proseguido por la variable que almacenar la data que va a ser leda. Por ejemplo:
int age; cin >> age;

se declara la variable age como un entero int y luego espera por una entrada desde cin (teclado) para almacenarla en esta variable entera.

cin solo puede procesar la entrada desde el teclado una vez que la tecla RETURN o ENTER sea presionada. Adems aunque usted pida un smbolo simple cin no procesara entrada hasta que el usuario no presione RETURN una vez que el smbolo halla sido

la

introducido. Usted debe considerar siempre el tipo de la variable que esta usando como un contenedor con la extraccin cin. Si esta esperando un entero usted tendr un entero, si pide un smbolo tendr un smbolo y si pide una cadena de smbolos tendr una cadena de smbolos.
// i/o example #include <iostream> using namespace std; int main () { int i; cout << "Please enter an integer value: "; cin >> i; cout << "The value you entered is " << i; cout << " and its double is " << i*2 << ".\n"; return 0; } Please enter an integer value: 702 The value you entered is 702 and its double is 1404.

El usuario del programa puede ser una de las razones que provoquen errores aun en el mas simple de los programas que usan cin (como el que acabamos de ver). Esto es debido a que si usted pide un valor entero y el usuario introduce un nombre (el cual es una cadena de smbolos), el resultado puede causar que su programa colapse ya que no era lo que se estaba esperando del usuario. Entonces cuando use la data proveda por un cin debe confiar que el usuario de su programa va cooperar totalmente y que no va a introducir su nombre cuando se le pida un valor entero. Mucho ms adelante, cuando veamos como usar cadenas de caracteres veremos posibles soluciones para los errores que puedan ser causados por este tipo de entradas de los usuarios. Puede usar tambin cin para pedir ms de un dato de entrada al usuario:
cin >> a >> b;

es equivalente a:
cin >> a; cin >> b;

En ambos casos el usuario debe dar dos datos, uno para la variable a y otro para la variable b que pueden estar separados por cualquier separador blank vlido: un espacio, un smbolo de tabulado o un nueva linea.

Seccin 2.1

Estructuras de Control
Un programa usualmente no est limitado a una secuencia lineal de instrucciones. Durante su proceso el puede bifurcar, repetir cdigo o tomar decisiones. Para este propsito ,C++ provee estructuras de control que sirven para especificar que ha de ser hecho para ejecutar nuestro programa. Con la introduccin de las secuencias de control vamos a tener que presentar un nuevo concepto: el bloque de instrucciones. un conjunto de instrucciones separado por punto y comas (;) pero agrupadas en un bloque delimitado por signos de llaves: { y }. La mayora de las estructuras de control que vamos a ver en esta seccin aceptan un extracto genrico como parmetro, este se refiere tanto a una simple instruccin o a un bloque de instrucciones, como queramos. Si queremos que el extracto sea una simple instruccin no necesitamos encerrarlo entre llaves ({}). Si queremos que el extracto sea de ms de una instruccin debemos encerrarlo entre llaves ({}) formando un bloque de instrucciones.

Estructura condicional: if y else


Es usada para ejecutar una instruccin o bloque de instrucciones solo si una condicin es cumplida. Su forma es:
if (condicin) extracto

donde la condicin es la expresin que serevaluada. Si esta condicin es true (verdadera), el extracto es ejecutado. Si esta es falsa (false), el extracto es ignorado (no ejecutado) y el programa continua en la siguiente instruccin despus de la estructura condicional.

por ejemplo, el siguiente fragmento de cdigo imprime x es 100 solo si el valor guardado en la variable x es en verdad 100:
if (x == 100) cout << "x es 100";

Si queremos ms de una instruccin para ser ejecutada en caso de que la condicin sea verdadera podemos especificar un bloque de instrucciones usando llaves { }:
if (x == 100) { cout << "x es "; cout << x; }

Podemos adicionalmente especificar que queremos que pase si la condicin no es cumplida mediante el uso de la palabra reservada else. su forma usada en conjuncin con if es:
if (condicin) extracto1 else extracto2

por ejemplo:
if (x == 100) cout << "x es 100"; else cout << "x no es 100";

imprime en la pantalla x es 100 si en realidad x vale 100, pero si no -y solo si no- imprime x no es 100.

La estructura if + else puede ser concatenada con la intencin de verificar un rango de valores. El siguiente ejemplo muestra su uso diciendo si el valor presente almacenado en x es positivo, negativo o ninguno de los anteriores, es decir, igual a cero.
if (x > 0) cout << "x else if (x < cout << "x else cout << "x es positivo"; 0) es negativo"; es 0";

Recuerde que en el caso que queramos que ms de una instruccin sea ejecutada, debemos agruparlas en un bloque de instrucciones usando llaves { }.

Estructuras de repeticin o lazos o bucles


los Lazos tienen como objetivo repetir un extracto un cierto nmero de veces o mientras una condicin sea cumplida. El lazo while. (repita mientras) Su formato es:
while (expresin) extracto

y su funcin es simplemente repetir el extracto mientras (while) la expresin sea verdadera.

Por ejemplo, vamos a hacer un programa de cuenta regresiva usando un bucle while:

// custom countdown using while #include <iostream> using namespace std; int main () { int n; cout << "Enter the starting number > "; cin >> n; while (n>0) { cout << n << ", "; --n; } cout << "FIRE!"; return 0; }

Enter the starting number > 8 8, 7, 6, 5, 4, 3, 2, 1, FIRE!

Cuando el programa arranque el usuario es forzado a insertar un nmero de partida para la cuenta regresiva. Luego el bucle while comienza, si el valor introducido por el usuario cumple con la condicin n>0 (que n es mayor que 0 ), el bloque de instrucciones que sigue ser ejecutado un nmero indefinido de veces mientras la condicin (n>0) permanezca verdadera. Todos los procesos en el programa arriba pueden ser interpretados de acuerdo al siguiente guin comenzando en main:

1. El usuario asigna el valor de n. 2. La instruccin while verifica si (n>0). A este punto hay dos posibilidades: o true: ejecuta el extracto (paso 3,) o false: salta el extracto. El programa sigue en el paso 5.. 3. Ejecute el extracto:
cout << n << ", "; --n; (imprime n en la pantalla y decrementa n en 1).

4. Fin del bloque. Retorna automticamente al paso 2. 5. Continua el programa despus del bloque: imprime FIRE! y fin del programa.

Debemos considerar que el lazo ha de terminar en el mismo punto, adems dentro del bloque de instrucciones (extracto del bucle ) debemos proveer algn mtodo que force a la condicin a volverse falsa en algn momento, de otra manera el lazo continuara por siempre. En este caso hemos incluido --n; que causa que la condicin se vuelva false despus de algunas repeticiones del lazo: cuando n se vuelve 0, que es cuando nuestra cuenta regresiva termina. Por supuesto esta es una accin tan simple para nuestro computador que la cuenta regresiva es realizada instantneamente sin un retardo practico entre nmeros.
El bucle do-while.(hacer mientras)

Formato:
do extracto while (condicin);

Su funcionalidad es exactamente igual al del bucle while excepto que la condicin en el do-while es evaluada despus de la ejecucin del extracto en ves de antes, garantizando al menos una ejecucin del extracto as la condicin nunca sea cumplida. Por ejemplo, el siguiente programa imprime cualquier nmero que introduzca hasta que introduzca 0.
// number echoer #include <iostream> using namespace std; int main () { unsigned long n; do { cout << "Enter number (0 to end): "; cin >> n; cout << "You entered: " << n << "\n"; } while (n != 0); return 0; } Enter number You entered: Enter number You entered: Enter number You entered: (0 to end): 12345 12345 (0 to end): 160277 160277 (0 to end): 0 0

El bucle do-while es usualmente utilizado cuando la condicin que ha de determinar su final es determinada dentro del extracto del lazo, como en el caso anterior, donde la entrada del usuario dentro del bloque de instrucciones es la que determina el fin del lazo. Si usted nunca introduce el valor 0 en el ejemplo previo el lazo nunca terminara.
El bucle for (repita para). Su formato es:
for (inicializacion; condicion; incremento) extracto;

y su funcion principal es repetir un extracto mientras la condicion siga siendo cierta, como en el bucle while. Pero ademas, for provee lugares para especificar una intruccion de inicializacion y una instruccion de incremento. Asi es te bucle esta especialmente diseado para desempear una accion repetitiva con un contador.

Este trabaja de la siguiente manera:


1, la inicializacion es ejecutada. Generalmente esto es la asignacion de un valor inicial para una variable contador. Esto es ejecutado una sola vez. 2, la condition es revisada, si esta es cierta true el bucle continua, de otra manera el

bucle finaliza y el extracto es saltado. 3, el statement es ejecutado. Como es habitual, este puede ser tanto una simple instruccion como un bloque de instrucciones encerrado entre llaves { }. 4, finalmente, lo que se haya especificado en el campo incremento es ejecutado y el bucle regresa al paso 2. Aqui esta un ejemplo de cuenta regresiva usando un bucle for.
// countdown using a for loop #include <iostream> using namespace std; int main () { for (int n=10; n>0; n--) { cout << n << ", "; } cout << "FIRE!"; return 0; } 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE!

Los campos inicializacion e incremento son opcionales. Ellos pueden ser obviados pero no asi los puntoycomas entre ellos. Por ejemplo pudireramos escribir: for (;n<10;) si no queremos especificar inicializacion ni incremento; o for (;n<10;n++) si queremos incluir un campo incremento pero no asi un campo inicializacion. Opcionalmete, usando el operador coma (,) podemos especificar mas de una instruccion en cualquiera de los campos incluidos en un bucle for, como en inicializacion, por ejemplo. El operador coma (,) es una instruccion de separacion, esta sirve para separar mas de una instruccion donde solo una generalmente es esparada. Por ejemplo, suponga que queriamos inicializar mas de una variable en nuestro bucle:
for ( n=0, i=100 ; n!=i ; n++, i-- ) { // whatever here... }

Este bucle ejecutara 50 veces si ninguna de las variables n o i son modificadas dentro del bucle:

n inicia en 0 e i en 100, la condicin es (n!=i) (que n sea distinto de i). Debido a que n

es incrementada de uno en uno e i decrementada de uno en uno, la condicion del bucle se hara false despues de la 50ma repeticion, cuando ambas n e i sean iguales a 50.

Bifurcaciones de control y saltos.


La instruccion break. Usando break podemos dejar un bucle incluso si su condicion de parada no esta satisfecha. Puede ser usada para finalizar un lazo infinito, o forzar su finalizacion antes de final natural. Por ejemplo, vamos a parar la cuenta regresiva antes de su finalizacion natural (una falla del motor posiblemente):
// break loop example #include <iostream> using namespace std; int main () { int n; for (n=10; n>0; n--) { cout << n << ", "; if (n==3) { cout << "countdown aborted!"; break; } } return 0; } 10, 9, 8, 7, 6, 5, 4, 3, countdown aborted!

La instruccion continue. La instruccion continue causa que el programa salte el resto del extracto dentro del bucle en la iteracion actual asi como si el final del extracto o bloque de instruccion es haya sido alcanzado, provocando el salto a la siguiente iteracion. Por ejemplo, vamos a saltar el numero 5 en nuestra cuenta regresiva:
// break loop example #include <iostream> using namespace std; int main () { for (int n=10; n>0; n--) { if (n==5) continue; cout << n << ", "; } cout << "FIRE!"; return 0; } 10, 9, 8, 7, 6, 4, 3, 2, 1, FIRE!

La instruccion goto.

Esta permite hacer un salto absoluto a otro punto del programa. Usted deberia usar esta herramienta cuidadosamente ya que su ejecucion ignora cualquier tipo de limitacion de anidamiento.

El punto de destino es identificado por una etiqueta, la cual es luego usada como argumento de la instruccion goto. Una etiqueta consiste de un identificador valido seguido por dos puntos (:). Esta instruccion no tiene una utilidad concreta en programacin estructurada o programacin orientada por objetos mas alla de la que aquellos fans de la programacin de bajo nivel puedan encontrarle. Por ejemplo, aqui esta nuestra cuenta regresiva usando goto:
// goto loop example #include <iostream> using namespace std; int main () { int n=10; loop: cout << n << ", "; n--; if (n>0) goto loop; cout << "FIRE!"; return 0; } 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE!

La funcion exit. exit es una funcion definida en la biblioteca cstdlib (stdlib.h).

El proposito de exit es terminar el programa que esta corriendo con un codigo especifico de salida. Su prototipo es:
void exit (int exit code);

El exit code es usado por algunos sistemas operativos y puede ser usado por llamadas de programas. Por convencion, un exit code de 0 significa que el programa finalizo normalmente y cualquier otro valor significa que ocurrio un error.

La estructura selectiva: switch.


La sintaxis de la instruccion switch es un poco peculiar. Su objetivo es verificar varios posibles valores constantes para una expresion, algo similar a lo que hicimos el principio de esta seccion con el encadenamiento de varias sentencias if y else if. Su forma es la siguiente:
switch (expresion) { case constante1:

bloque de instruciones 1 break; case constante2: bloque de instrucciones 2 break; . . . default: bloque de instrucciones por omision }

Esto trabaja de la siguiente manera: switch evalua expresion y verifica si el valor de este es equivalente a la constante1, si es asi, el ejecuta el bloque de instrucciones 1 hasta que encuentre la palabre reservada break, luego el programa saltara al final de la estructura selectiva switch. Si expression no era igual a constante1 esta revisara si expresion es equivalente a constante2. Si lo es, se ejecutara el bloque de instrucciones 2 hasta que encuentre la palabra reservada break. Finalmente, si el valor de expresion no ha concordado con ninguna de las constantes especificadas previamente (se puede especificar tantas sentencias case como valores se quiera verificar), el programa ejecutara las instrucciones incluidas en la seccion default:, si esta existe, ya que es opcional.

Ambos de los siguientes fragmentos de codigo son equivalentes:


ejemplo de switch
switch (x) { case 1: cout << "x is 1"; break; case 2: cout << "x is 2"; break; default: cout << "value of x unknown"; }

equivalente if-else
if (x == 1) { cout << "x is 1"; } else if (x == 2) { cout << "x is 2"; } else { cout << "value of x unknown"; }

Hemos comentado anteriormente que la sintaxis de la instruccion switch es un poco peculiar. Note la inclusion de las instrucciones break al final de cada bloque. Esto es necesario porque si, por ejemplo, no hubiesemos incluido esta al final del bloque de instrucciones 1 el programa no hibiese saltado al final del bloque de la estructura selectiva switch (}) y esta hubiese continuado ejecutando el resto de los bloques de instrucciones hasta la primera aparicion de la instruccio break o hasta el final del bloque de

la estructura selectiva switch. Esto hace que sea innecesario incluir llaves { } en cada uno de los casos, y esto puede ser muy util para ejecutar el mismo bloque de instrucciones para diferentes posibles valores de la expresion evaluada. Por ejemplo:
switch (x) { case 1: case 2: case 3: cout << "x is 1, 2 or 3"; break; default: cout << "x is not 1, 2 nor 3"; }

Note que switch solo puede ser usada para comparar una expresion con diferentes constantes. Debido a esto no podemos colocar variables (case (n*2):) o rangos (case (1..3):) porque estas no son constantes validas.

Si necesita revisar rangos o valores que no son constanes usa concatenacion de sentencias if y else if.

Seccin 2.2

Funciones (I)
Usando funciones podemos estructurar nuestros programas en un modo ms modular, accesando a todo el potencial que la programacin estructurada en C++ nos puede ofrecer. Una funcin es un bloque de instrucciones que es ejecutado cuando es llamado desde algn otro punto del programa. Su formato es el siguiente:
tipo nombre ( argumento1, argumento2, ...) declaracin

donde:
tipo es el tipo de dato retornada por la funcin. nombre es el nombre por el cual ser posible llamar a la funcin. argumentos (se pueden especificar tantos como se quiera). Cada argumento consiste en un

tipo de dato seguido por su identificador, como en una declaracin de variable (por ejemplo, int x) y el cual acta dentro de la funcin como cualquier otra variable. Los argumentos permiten pasar parmetros a la funcin cuando es llamada. Los diferentes parmetros estn separados por comas. declaracin es el cuerpo de la funcin. Puede ser una sola instruccin o un bloque de instrucciones. En el ltimo caso debe estar delimitado por corchetes {}.

Aqu est el primer ejemplo:

// function example #include <iostream.h> int addition (int a, int b) { int r; r=a+b; return (r); } int main () { int z; z = addition (5,3); cout << "El resultado es " << z; return 0; }

El resultado es 8

Para examinar este cdigo, primero que todo recuerde algo dicho al principio de este tutorial: un programa en C++ siempre comienza su ejecucin con la funcin main. As que empezaremos ah. Podemos ver que como la funcin main comienza declarando la variable z de tipo entero (int). Justo despus vemos una llamada a la funcin addition. Si ponemos atencin podremos ver la similitud entre la estructura de la llamada a la funcin y la declaracin de la funcin en las lineas de cdigo superiores:

Los parmetros tienen una clara correspondencia. Dentro de la funcin main llamamos a addition pasando 2 valores: 5 y 3 que correspon a los parmetros int a y int b, declarados para la funcin addition.

En el momento en el cual la funcin es llamada desde el main, el control es perdido por main y es pasado a la funcin addition. El valor de ambos parmetros pasados en la llamada (5 y 3) son copiados a las variables locales int a y int b dentro de la funcin. La funcin addition declara una nueva variable (int r;), y por el significado de la expresin r=a+b;, asigna a r el resultado de a ms b. Como los parmetros pasados para a y b son 5 y 3 respectivamente, el resultado es 8. La siguiente lnea de cdigo:
return (r);

finaliza la funcin addition, y retorna el control a la funcin que la llam (main) siguiendo el programa desde el mismo punto en el cual fue interrumpida por la llamada a addition. Pero adicionalmente, return fue llamado con el contenido de la variable r (return (r);), la cual era 8 en ese momento, as que este valor se dice que es retornado por la funcin.

El valor retornado por una funcin es el valor dado a la funcin cuando es evaluada. por eso, z almacenar el valor retornado por addition (5, 3), que es 8. Para explicarlo de otra manera, puede imaginarse que la llamada a una funcin (addition (5,3)) es literalmente reemplazada por el valor que retorna (8).

La siguiente lnea de cdigo en main es:


cout << "El resultado es " << z;

que, como ya puede suponer, produce la impresin del resultado en la pantalla. Alcance de variables [re]

Debe considerar que el alcance de variables declaradas dentro de una funcin o cualquier otro bloque de instrucciones es solo su propia funcin o su propio bloque de instrucciones y no puede ser usada fuera de ellos. Por ejemplo, en el ejemplo previo habra sido imposible usar las variables a, b or r directamente en la funcin main porque eran variables locales a la funcin addition. Tambin, habra sido imposible usar la variable z directamente dentro de la funcin addition, porque era una variable local a la funcin main. Por eso, el alcance de las variables locales est limitado al mismo nivel de anidado en el cual estn declarados. Sin embargo tambin puede declarar variables (globales) global que son visibles desde cualquier punto del cdigo, dentro y fuera de cualquier funcin. Para declarar variables globales debe hacerlo fuera de cualquier funcin o bloque de instrucciones, lo cual significa, directamente en el cuerpo del programa.

Y aqu est otro ejemplo sombre funciones:


// function example #include <iostream.h> int subtraction (int a, int b) { int r; r=a-b; return (r); } int main () { int x=5, y=3, z; z = subtraction (7,2); cout << "The first result is " << z << '\n'; cout << "The second result is " << subtraction (7,2) << '\n'; cout << "The third result is " << subtraction (x,y) << '\n'; z= 4 + subtraction (x,y); cout << "The fourth result is " << z << '\n'; return 0; } The The The The first result is 5 second result is 5 third result is 2 fourth result is 6

En este caso hemos creado la funcin subtraction. La nica cosa que esta funcin hace es restar ambos parmetros y retornar el resultado. Sin embargo, si examinamos la funcin main veremos que hemos hecho muchas llamadas a la funcin subtraction. Hemos usado algunos diferentes mtodos de llamada para que usted vea otros modos o momentos cuando una funcin puede ser llamada. Para entender bien estos ejemplos debe considerar una vez ms que una llamada a una funcin puede ser perfectamente reemplazada por su valor de retorno. Por ejemplo, el primer caso (que ya debera conocer porque es el mismo patrn que hemos usado en ejemplos previos):
z = subtraction (7,2); cout << "The first result is " << z;

If we replace the function call by its result (that is 5), we would have:
z = 5; cout << "The first result is " << z;

As como
cout << "The second result is " << subtraction (7,2);

tiene el mismo resultado como la llamada previa, pero en este caso hicimos la llamada a subtraction directamente como un parmetro para cout. Simplemente imagine que que hubiesemos escrito:
cout << "The second result is " << 5;

ya que 5 es el resultado de subtraction (7,2).

En el caso de
cout << "The third result is " << subtraction (x,y);

La nica cosa nueva es que los parmetros de subtraction son variables en vez de constantes. Eso es perfectamente vlido. En este caso los valores pasados a la funcin subtraction son los valores de x y y, que son 5 y 3 respectivamente, dando 2 como resultado.

El cuarto caso es ms de lo mismo. Simplemente note que en vez de:


z = 4 + subtraction (x,y);

podramos haber puesto:


z = subtraction (x,y) + 4;

con el mismo resultado. Dese cuenta que el signo de punto y coma (;) va al final de la expresin completa. No necesariamente tiene que ir justo despus de la llamada a la funcin. La explicacin podra ser una vez ms que imagine que una funcin puede ser reemplazada por su resultado:
z = 4 + 2; z = 2 + 4;

Funciones sin tipo. El uso de void.


Si recuerda la sintaxis de una declaracin de funcin:
tipo nombre ( argumento1, argumento2 ...) declaracin

ver que es obligatorio que esta declaracin comienza con un tipo, que es el tipo de dato que ser retornado por la funcin con la instruccin return. Pero qu pasa si no queremos retornar ningn valor?

Imagine que queremos hacer una funcin slo para mostrar un mensaje en la pantalla. No necesitamos que retorne ningn valor, ms an, no necesitamos que reciva ningn parmetro. Para estos casos, el tipo void fue ideado en el lenguaje C. Mire esto:

// void function example #include <iostream.h> void dummyfunction (void) { cout << "I'm a function!"; } int main () { dummyfunction (); return 0; }

I'm a function!

Aunque en C++ no es necesario especificar void, su uso es considerado conveniente para significar que es una funcin sin parmetros o argumentos y no algo ms. Lo que debe estar siempre pendiente es que el formato para llamar una funcin incluye especificar su nombre y encerrando los argumentos dentro de parntesis. La no existencia de argumentos no nos exime de la obligacin de usar parntesis. Por esa raz la llamada a dummyfunction es
dummyfunction ();

Esto claramente indica que es una llamada a una funcin y no el nombre de una variable o algo ms.

Seccin 2.3

Funciones (II) Argumentos pasados por valor y por referencia.


Hasta ahora, en todas las funciones que hemos visto, los parmetros pasados a las funciones han sido pasados por valor. Esto significa que cuando llamamos a una funcin con parmetros, lo que pasamos a la funcin son valores pero nunca las variables especificadas por si mismas. Por ejemplo, suponga que hemos llamado a nuestra primera funcin addition usando el siguiente cdigo :
int x=5, y=3, z; z = addition ( x , y );

Lo que hicimos en este caso fue llamar a la funcin addition pasndole los valores de x y y, esto es: 5 y 3 respectivamente, no las variables por si mismas.

De esta manera, cuando la funcin addition est siendo llamada, el valor de sus variables a y b se transforman en 5 y 3 respectivamente, pero cualquier modificacin de a o b dentro de la funcin addition no afectar los valores de x y y fuera de ella, porque las variables x y y no fueron pasadas por si mismas a la funcin, solamente sus valores. Pero podran existir algunos casos donde necesite manipular desde una funcin el valor de una variable externa. Para este propsito tenemos que usar argumentos pasados por referencia, como en la funcin duplicate del siguiente ejemplo:
// pasando parametros por referencia #include <iostream.h> void duplicate (int& a, int& b, int& c) { a*=2; b*=2; c*=2; } int main () { int x=1, y=3, z=7; duplicate (x, y, z); cout << "x=" << x << ", y=" << y << ", z=" << z; return 0; } x=2, y=6, z=14

Lo primero que debe llamar su atencin es que en la declaracin de duplicate el tipo de cada argumento est seguido por un caracter ampersand (&), que sirve para especificar que la variable va a ser pasada por by referencia en vez de ser pasada por valor, como es usual. Cuando se pasa una variable por referencia estamos pasando la variable por si misma y cualquier modificacin que hagamos a tal parmetro dentro de la funcin tendr efecto en dicha variable fuera de la funcin.

Para decirlo de otra forma, hemos asociado a, b y c con los parmetros usados cuando se llam a la funcin (x, y y z) y cualquier cambio que hagamos sobre a dentro de la funcin afectar el valor de x afuera. Cualquier cambio que hagamos sobre b afectar y, e igualmente con c y z.

Por eso la salida de nuestro programa, que muestra los valores almacenados en x, y y z luego de la llamada a duplicate, muestra los valores duplicados de las tres variables de main. Si hubiesemos declarado la funcin:
void duplicate (int& a, int& b, int& c)

como:
void duplicate (int a, int b, int c) o sea, sin los ampersand (&), no habramos pasado

las variables por referencia, sino sus valores, y por consiguiente, la salida por pantalla para nuestro programa habr sido los valores de x, y y z sin haber sido modificados. Este tipo de declaracin "por referencia" usando el caracter ampersand (&) es exclusivo de C++. En el lenguaje C tendramos que utilizar punteros para hacer algo equivalente. Pasar variables por referencia es una efectiva forma de permitirle a una funcinn retornar ms de un valor. Por ejemplo, aqu est una funci que retorna el anterior y prximo nmero del primer argumento.
// Retornando mas de un valor #include <iostream.h> void prevnext (int x, int& prev, int& next) { prev = x-1; next = x+1; } int main () { int x=100, y, z; prevnext (x, y, z); cout << "Previous=" << y << ", Next=" << z; return 0; } Previous=99, Next=101

Valores por defecto en argumentos.


Cuando declaramos una funcin podemos especificar un valor por defecto para cada parmetro. Este valor ser utilizado si el parmetro es dejado en blanco cuando se llama a la funcin. Para hacer esto, simplemente tenemos que asignar un valor a los argumentos en la declaracin de la funcin. Si no es pasado ningn valor para ese parmetro cuando la funcin es llamada, se utiliza el valor por defecto, pero si es especificado alguno, este valor por defecto es omitido y se utiliza el valor pasado. Por ejemplo:

// valores por defecto en funciones #include <iostream.h> int divide (int a, int b=2) { int r; r=a/b; return (r); } int main () { cout << divide (12); cout << endl; cout << divide (20,4); return 0; }

6 5

Como podemos ver en el cuerpo del programa hay dos llamadas a la funcin divide. En la primera:
divide (12)

hemos especificado slo un argumento, pero la funcin divide permite hasta dos. As que la funcin divide ha asumido que el segundo parmetro es 2 ya que es lo que hemos especificado que pase si este parmetro est faltando (ntese la declaracin de la funcin, la cual termina con int b=2). Por lo tanto el resultado de la llamada a esta funcin es 6 (12/2). En la segunda llamada:
divide (20,4)

hay 2 parmetros, por lo tanto la asignacin por defecto (int b=2) es sobreescrita por el parmetro pasado, que es 4, haciendo el resultado igual a 5 (20/4).

Funciones sobrecargadas.
Dos funciones diferentes pueden tener el mismo nombre si los prototipos de sus argumentos son diferentes, lo cual significa que puede darle el mismo nombre a ms de una funcin si tienen diferente n&mero de argumentos o diferentes tipos en sus argumentos. Por ejemplo,
// Funciones sobrecargadas #include <iostream.h> int divide (int a, int b) { return (a/b); } 2 2.5

float divide (float a, float b) { return (a/b); } int main () { int x=5,y=2; float n=5.0,m=2.0; cout << divide (x,y); cout << "\n"; cout << divide (n,m); cout << "\n"; return 0; }

En este caso hemos definido dos funciones con el mismo nombre, pero una de ellas acepta dos argumentos de tipo int y la otra los acepta de tipo float. El compilador sabes a cual llamar en cada caso examinando los tipos cuando la funcin es llamada. Si es llamada con dos argumentos tipo int llama a la funcin que tienen dos argumentos tipo int en su prototipo y si es llamada con dos argumentos tipo float llamar a la que tiene dos argumentos tipo float en su prototipo. Por simplicidad he incluido el mismo cdigo dentro de ambas funciones, pero esto no es obligatorio. Puede hacer dos funciones con el mismo nombre pero con comportamientos completamente diferentes.

Funciones inline.
La directiva inline puede ser incluida antes de la declaracin de una funcin para especificar que la funcin debe ser compilada como cdigo en el mismo punto donde es llamada. Esto es equivalente a declarar un macro. Su ventaja es solo apreciada en funciones muy cortas, en las cuales el cdigo resultante de compilar el programa puede ser ms rpido si se puede evitar el gasto de llamar la funcin (apilamiento de arguments). El formato para esta declaracin es:
inline type name ( argumentos ... ) { instrucciones ... }

y la llamada es como la llamada a cualquier otra funcin. No es necesario incuir la palabra clave inline antes de cada llamada, solamente en la declaracin.

Recursividad.
Recursividad es la propiedad que tienen las funciones de ser llamadas por ellas mismas. Es til para tareas como algunos mtodos de ordenamiento o para calcular el factorial de un nmero. Por ejemplo, para obtener el factorial de un numero (n) su frmula matemtica es:
n! = n * (n-1) * (n-2) * (n-3) ... * 1

ms concretamente, 5! (factorial de 5) sera:


5! = 5 * 4 * 3 * 2 * 1 = 120

y una funcin recursiva para hacer esto podra ser:


// calculador de factoriales #include <iostream.h> long factorial (long a) { if (a > 1) return (a * factorial (a-1)); else return (1); } int main () { long l; cout << "Type a number: "; cin >> l; cout << "!" << l << " = " << factorial (l); return 0; } Type a number: 9 !9 = 362880

Ntese como en la funcin factorial incluimos una llamada a ella misma, pero solamente si el argumento es mayor que 1, ya que de otra manera la funcin realizara un ciclo infinito recursivo en el cual una vez que llegue a 0 continuara multiplicando por todos los nmeros negativos (probablemente provocando un error de desborde de pila en tiempo de ejecucin). Esta funcin tiene una limitacin por el tipo de dato usado en su diseo (long) para mayor simplicidad. En un sistema estandar, el tipo long no permitira almacenar factoriales mayores que 12!.

Prototipos de funciones.
Hasta ahora, hemos definido todas las funciones antes de la primera aparicin de llamadas a ellas, que generalmente es en el main, dejando la funcin main para el final. Si trata de repetir algunos ejemplos de funciones descritas hasta ahora, pero colocando la funcin main antes que cualquier otra funcin que es llamada dentro de esta, obtendra un error. La razn es que para poder llamar a una funcin debe haber sido declarada previamente (debe ser conocida), como hemos hecho en nuestros ejemplos. Pero hay una manera alternativa para evitar escribir todo el cdigo de todas las funciones antes de que puedan ser usadas en el main o en cualquier funcin. Consiste en hacer prototipos de funciones. Esto consiste en hacer una declaracin previa y ms corta, pero con mucho significado, de la definicin completa para que el compilador pueda conocer los tipos de datos de los argumentos y valor de retorno. Su forma es:

tipo nombre ( argumento_tipo1, argumento_tipo2, ...);

Es identico al encabezado de una definicin de una funcin, excepto que:

No incluye ninguna instruccin para la funcin. Esto significa que no incluye el cuerpo con todas las instrucciones que son usualmente encerradas dentro de llaves { }. Termina con un punto y coma (;). En la enumeracin de argumentos es suficiente con poner el tipo de cada argumento. La inclusin de un nombre para cada argumento en la definicin como en una funcin standard es opcional, aunque recomendada.

Por ejemplo:
// Prototipos #include <iostream.h> void odd (int a); void even (int a); int main () { int i; do { cout << "Type a number: (0 to exit)"; cin >> i; odd (i); } while (i!=0); return 0; } void odd (int a) { if ((a%2)!=0) cout << "Number is odd.\n"; else even (a); } void even (int a) { if ((a%2)==0) cout << "Number is even.\n"; else odd (a); } Type a Number Type a Number Type a Number Type a Number number (0 is odd. number (0 is even. number (0 is even. number (0 is even. to exit): 9 to exit): 6 to exit): 1030 to exit): 0

Este ejemplo no es realmente un ejemplo de efectividad, Estoy seguro que en este punto usted puede hacer un programa con el mismo resultado usando slo la mitad de las lneas de cdigo. Pero este ejemplo ilustra como trabajan los prototipos. Adems, en este caso concreto el prototipo de -al menos- una de las dos funciones es necesario. Las primeras cosas que vemos son los prototipos de las funciones odd y even:

void odd (int a); void even (int a);

Esto permite a estas funciones ser usadas antes de ser definidas completamente, por ejemplo, en el main, el cual est ahora puesto en un lugar ms lgico: El principio del codigo del programa. Sin embargo, la razn especfica por la cual este programa necesita al menos una de las funciones con prototipo es porque en odd hay una llamada a even y en even hay una llamada a odd. Si ninguna de las dos funciones hubiesen sido declaradas previamente, ocurrira un error, ya que o odd no sera visible desde even (porque no ha sido declarada an), o even no sera visible desde odd. Muchos programadores recomiendan que todas las funciones tengan prototipo. Es tambin mi recomendacin, principalmente en caso de que existan muchas funciones o en caso de que sean muy largas. Tener los prototipos de todas las funciones en un mismo lugar puede ahorrarnos algn tiempo para determinar como llamarla o inclusive facilitar la creacin de un archivo de cabezera.

Seccin 3.1

Arreglos
Arreglos son una serie de elementos (variables) del mismo tipo colocadas consecutivamente en la memoria, que pueden ser referenciados individualmente agregando un indice a un nico nombre. Esto significa que, por ejemplo, podemos almacenar 5 valores de tipo int sin tenerque declarar 5 variables diferentes con un identificador diferente. Sino que, usando un arreglo podemos almacenar 5 diferentes valores del mismo tipo, int por ejemplo, con un nico identificador. Por ejemplo, un arreglo para contener 5 valores enteros de tipo int llamado billy podra ser representada de esta manera:

donde cada celda en blanco representa un elemento del arreglo, que en este caso son valores enteros de tipo int. Estos estn numerados desde 0 hasta 4 ya que en los arreglos el primer ndice es siempre 0, independientemente de su largo.

Como cualquier otra variable, un arreglo debe ser declarada antes de ser usada. Una declaracin tpica para un arreglo en C++ es:

tipo nombre [elementos];

donde tipo es un tipo de objeto vlido (int, float...), nombre es un identificador de variable vlido y el campo elementos, que est encerrado entre corchetes [], especifica cuantos de estos elementos contiene el arreglo.

Por lo tanto, para declarar billy como se mostr arriba es tan simple como lo siguiente:
int billy [5];

NOTA: El campo elementos entre corchetes [] cuando se declara un arreglo debe ser un valor constante, ya que los arreglos son bloques de memoria esttica de un tamao dado y el compilador debe ser capaz de determinar exactamente cuanta memoria debe asignar al arreglo antes de considerar cualquier instruccin.

Inicializando arreglos.
Cuando se declara un arreglo de alcance local (dentro de una funcin), si no se especifica, no ser inicializado, as que su contenido es indeterminado hasta que almaecenemos algunos valores en l.

Si declaramos un arreglo global (fuera de todas las funciones) su contenido ser inicializado con todos sus elementos llenos con ceros. As, si en el alcance global declaramos:
int billy [5];

cada elemento de billy se inicializar con 0:

Pero adicionalmente, cuando hemos declarado un arreglo, tenemos la posibilidad de asignar valores iniciales a cada uno de sus elementos usando llaves { }. Por ejemplo:
int billy [5] = { 16, 2, 77, 40, 12071 };

Esta declaracin habra creado un arreglo como el siguiente:

El nmero de elementos en el arreglo que hemos inicializado usando llaves { } debe coincidir con el largo en elementos que hemos declarado para el arreglo encerrado entre corchetes [ ]. Por

ejemplo, en el ejemplo del arreglo billy hemos declarado que tiene 5 elementos y en la lista de valores iniciales dentro de llaves { } hemos puesto 5 valores, uno para cada elemento.

Ya que esto puede ser considerado una repeticin inutil, C++ incluye la posibilidad de dejar en blanco los corchetes [ ] y el tamao del arrego ser definido por el nmero de valores incluidos entre las llaves { }:
int billy [] = { 16, 2, 77, 40, 12071 };

Acceso a los valores de un arreglo.


En cualquier punto del programa en el cual el arreglo es visible podemos acceder individualmente a cualquiera de sus valores para lectura o modificacin como si fuera una variable normal. El formato es el siguiente:
nombre[indice]

Siguiendo los ejemplos previos en los cuales billy tena 5 elementos y cada uno de ellos era de tipo int, el nombre que podemos utilizar para referirnos a cada elemento es el siguiente:

Por ejemplo, para almacenar el valor 75 en el tercer element de billy una posible sentencia sera:
billy[2] = 75;

y por ejemplo, para pasar el valor del tercer elemento de billy a la variable a, podramos escribir:
a = billy[2];

Por lo tanto, para todo propsito, la expresin billy[2] es como cualquier otra variable de tipo int.

Observe que el tercer elemento de billy es especificado por billy[2], ya que el primero es billy[0], el segundo es billy[1], y por lo tanto, el tercero es billy[2]. Por esta misma razn, su ltimo elemento es billy[4]. Ya que si escribimos billy[5], estaramos accediendo al sexto elemento de billy y por consiguiente excediendo el tamao del arreglo. En C++ es perfectamente vlido exceder el rango vlido de indices para un arreglo, Lo cual puede crear problemas ya que ellos no causan errores de compilacin pero pueden causar resultados inesperados o serios errores durante la ejecucin. La razn por la cual esto es permitido ser vista ms adelante cuando empecemos a usar punteros. En este punto es importante ser capaz de distinguir claramente entre los dos usos que los corchetes [ ] tienen para los arreglos. Ellos realizan dos diferentes tareas: una es determinar el tamao de los arreglos cuando se declaran; y la otra es especificar indices

para un elemento concreto en el arreglo cuando se hace referencia a este. Debemos simplemente tener cuidado de no confundir estos dos posibles usos de los corchetes [ ] con arreglos:
int billy[5]; nombre de tipo) billy[2] = 75; // declaracion de un nuevo arreglo (empieza con un // accede a un elemento del arreglo.

Otras operaciones vlidas con arreglos:


billy[0] = a; billy[a] = 75; b = billy [a+2]; billy[billy[a]] = billy[2] + 5; // ejemplo de arreglos #include <iostream.h> int billy [] = {16, 2, 77, 40, 12071}; int n, result=0; int main () { for ( n=0 ; n<5 ; n++ ) { result += billy[n]; } cout << result; return 0; } 12206

Arreglos Multidimensionales
Arreglos multidimensionales pueden ser descritos como arreglos de arreglos. Por ejemplo, un arreglo bidimensional se puede imaginar como una tabla bidimensional de un tipo de dato concreto y uniforme.

jimmy representa un arreglo bidimensional de 3 por 5 valores de tipo int. La manera de declarar

este arreglo sera:


int jimmy [3][5];

y por ejemplo, la manera de referenciar el segundo elemento verticalmente y cuarto horizontalmente en una expresin sera:
jimmy[1][3]

(recuerde que los indices de un arreglo always comienzan por 0). Los Arreglos multidimensionales no estn limitados a dos indices (dos dimensiones). Pueden contener tantos indices como sea necesario, aunque es raro tener que representar ms de 3 dimensiones. Solo considere la cantidad de memoria que un arreglo con muchos indices puede requerir. Por ejemplo:
char century [100][365][24][60][60];

assigna un char para cada segundo contenido en un siglo, que es ms de 3 mil millones de chars! Esto consumira cerca de 3000 megabytes de memoria RAM si pudieramos declararlo.

Los arreglos multidimensionales no son ms que una abstraccin, ya que podemos obtener los mismos resultados con un simple arreglo poniendo un factor entre sus indices:
int jimmy [3][5]; es equivalente a to int jimmy [15]; (3 * 5 = 15)

Con la salvedad de que el compilador recuerda por nosotros la profundidad de cada dimensin imaginaria. Sirva como ejemplos estos dos cdigos, con el mismo resultado, uno usando arreglos bidimensional es y el otro usando solo arreglos simples:
// Arreglos multidimensionales #include <iostream.h> #define WIDTH 5 #define HEIGHT 3 int jimmy [HEIGHT][WIDTH]; int n,m; int main () { for (n=0;n<HEIGHT;n++) for (m=0;m<WIDTH;m++) { jimmy[n][m]=(n+1)*(m+1); } // arreglos pseudomultidimensionales #include <iostream.h> #define WIDTH 5 #define HEIGHT 3 int jimmy [HEIGHT * WIDTH]; int n,m; int main () { for (n=0;n<HEIGHT;n++) for (m=0;m<WIDTH;m++) { jimmy[n * WIDTH +

return 0; }

m]=(n+1)*(m+1); } return 0; }

ninguno de estos programas producen salida por la pantalla, pero ambos asignan valores al bloque de memoria llamado jimmy de la siguiente manera:

Hemos usado constantes definidas (#define) para simplificar posibles modificaciones futuras del programa, por ejemplo, en caso de que decidamos aumentar el arreglo a una altura de 4 en vez de 3 podramos hacerlo cambiando la lnea:
#define HEIGHT 3

por
#define HEIGHT 4

sin necesidad de hacer otra modificacin al programa.

Arreglos como parmetros


En algn momento podramos necesitar pasar un arreglo como parmetro a una funcin. En C++ no es posible pasar por valor un bloque completo de memoria como parmetro a una funcin, inclusive si est ordenando como un arreglo, pero es permitido pasar su direccin. Esto tiene casi el mismo efecto prctico y es mucho ms rpido y ms eficiente.

Para poder admitir arreglos como parmetros la nica cosa que debemos hacer hacer cuando declaramos la funcin es especificar en el argumento el tipo de base para el arreglo, un identificador y un par de corchetes vacos []. Por ejemplo, la siguiente funcin:
void procedure (int arg[])

admite un parmetro de tipo "Arreglo de int" llamado arg. Para poder pasar a esta funcin un arreglo declarado como:
int myarray [40];

sera suficiente con escribir la llamada as:


procedure (myarray);

Aqu tiene un ejemplo completo:


// arreglos como parametros #include <iostream.h> void printarray (int arg[], int length) { for (int n=0; n<length; n++) cout << arg[n] << " "; cout << "\n"; } int main () { int firstarray[] = {5, 10, 15}; int secondarray[] = {2, 4, 6, 8, 10}; printarray (firstarray,3); printarray (secondarray,5); return 0; } 5 10 15 2 4 6 8 10

Como puede ver, el primer argumento (int arg[]) admite cualquier arreglo de tipo int, sin importar cual sea su largo. Por esa razn hemos incluido un segundo parmetro que le dice a la funcin el largo de cada arreglo que le pasemos como primer parmetro. Esto permite al ciclo for que imprime el arreglo, conocer el rango para chequear en el arreglo pasado. En la declaracin de una funcin es tambin posible incluir arreglos multidimensionales. El formato para un arreglo tridimensional es:
tipo_base[][profundidad][profundidad]

por ejemplo, una funcin con un arreglo multidimensional como argumento podra ser:
void procedure (int myarray[][3][4])

observe que los primeros corchetes [] estn vacos y los siguientes no. Esto debe ser siempre as porque el compilador debe poder determinar dentro de la funcin cual es la profundidad de cada dimensin adicional.

Los arreglos, tanto simples como multidimensionales, pasados como parmetros a funciones son una fuente comn de errores para programadores con poca experiencia. Yo recomiendo la lectura del captulo 3.3, Punteros para un mejor entendimiento de las operciones con arreglos.

Seccin 3.2

Cadenas de caracteres

En todos los programas vistos hasta ahora, hemos usado solo variables numricas, usadas para expresar nmeros exclusivamente. Pero adems de las variables numricas tambin existen cadenas de caracteres, que permiten representar sucesiones de caracteres, como palabras, oraciones, nombres, textos, etc. Hasta ahora las hemos usado como constantes, pero nunca hemos considerado variables capaces de contenerlas. En C++ no hay un tipo de variable elemental para almacenar cadenas de caracteres. Para lograrlo, podemos usar arreglos de tipo char, los cuales son sucesiones de elementos char. Recuerde que este tipo de dato (char) es el usado para almacenar un nico caracter, por esa razn los arreglos de ellos son generalmente usados para hacer cadenas de caracteres. Por ejemplo, el siguiente arreglo (o cadena de caracteres):
char jenny [20];

puede almacenar una cadena de hasta 20 caracteres. Puede imaginarlo as:

Este tamao mximo de 20 caracteres no requiere siempre estar completamente usado. Por ejemplo, jenny podra almacenar en algn momento en un programa o la cadena "Hello" o la cadena "Merry christmas". Por consiguiente, ya que el arreglo de caracteres puede almacenar cadenas ms cortas que su largo total, una convencin ha sido alcanzada para terminar el contenido vlido de una cadena con un caracter nulo, cuya constante puede ser escrita 0 o '\0'. Podramos representar jenny (un arreglo de 20 elementos de tipo char) almacenando la cadena de caracteres "Hello" y "Merry Christmas" de la forma siguiente:

Observe como despus del contenido vlido un caracter nulo ('\0') es incluido para indicar el fin de la cadena. Las celdas en gris representan valores indeterminados.

Inicializacin de cadenas
Ya que las cadenas de caracteres son arreglos ordinarios, las mismas reglas aplican. Por ejemplo, si queremos inicializar una cadena de caracteres con valores predeterminados podemos hacerlo como en cualquier otro arreglo:
char mystring[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

En este caso habramos declarado una cadena de caracteres (arreglo) de 6 elementos de tipo char inicializada con los caracteres que componen Hello ms el caracter nulo '\0'.

Sin embargo, las cadenas de caracteres tienen una forma adicional de inicializar sus valores: usando cadenas constantes. En las expresiones que hemos usado en ejemplos en captulos previos, constantes que representaban cadenas completas han aparecido muchas veces. Estas son especificadas encerradas entre comillas dobles ("), por ejemplo:
"el resultado es: "

es una cadena constante que probablemente hemos usado en alguna ocasin. A diferencia de las comillas simples (') que especifican un nico caracter constante, las comillas dobles (") son constantes que especifican una sucesin de caracteres. Cadenas encerradas entre comillas dobles siempre tienen un caracter nulo ('\0') automticamente aadido al final. Por consiguiente podramos inicializar la cadena mystring con valores por cualquiera de estas dos maneras:
char mystring [] = { 'H', 'e', 'l', 'l', 'o', '\0' }; char mystring [] = "Hello";

En ambos casos el arreglo o cadena de caracteres mystring es declarado con un tamao de 6 caracteres (elementos de tipo char): los 5 caracteres que componen Hello ms un caracter nulo al final ('\0') lo cual especifica el final de la cadena y que, en el segundo caso, cuando se usaron las comillas dobles (") es automticamente aadido. Antes de continuar, dese cuenta que la asignacin de multiples constantes con comillas dobles (") a arreglos es slo vlida cuando se inicializa el arreglo, o sea, al momento de ser declarado. Expresiones como:
mystring = "Hello"; mystring[] = "Hello";

no son vlidas para arreglos, ni tampoco:


mystring = { 'H', 'e', 'l', 'l', 'o', '\0' };

As que recuerde: Podemos "asignar" una constante mltiple a un arreglo slamente al momento de inicializarlo. La razn ser ms comprensible cuando conozca un poco ms sobre apuntadores, ya que entonces se aclarar que un arreglo es simplemente un apuntador constante apuntando a una localidad de memoria. Y por ser constante, no se puede asignar al arreglo en si cualquier valor, pero si podemos asignar valores a cada elemento del arreglo. El momento de inicializar un arreglo es un caso especial, ya que no es una asignacin, aunque se use el mismo signo igual (=). De cualquier manera, siempre tenga presente la regla subrayada.

Asignando valores a cadenas

Ya que slamente se pueden asignar valores a los elementos de un arreglo individualmente y no al arreglo entero, sera vlido asignar una cadena de caracteres a un arreglo de char usando un mtodo como este:
mystring[0] mystring[1] mystring[2] mystring[3] mystring[4] mystring[5] = = = = = = 'H'; 'e'; 'l'; 'l'; 'o'; '\0';

Pero como usted puede pensar, esto no parece ser un mtodo muy prctico. Generalmente para asignar valores a un arreglo, y ms especificamente para una cadena de caracteres, se usan una serie de funciones como strcpy. strcpy (string copy) est definida en la biblioteca cstring (string.h) y puede ser llamada de la siguiente manera:
strcpy (string1, string2); Esto copia el contenido de string2

en string1. string2 puede ser un arreglo, un apuntador, o una cadena constante, as que la siguiente lnea ser una forma vlida de asignar la cadena constante "Hello" a mystring:
strcpy (mystring, "Hello");

Por ejemplo:
// asignandole valor a una cadena #include <iostream.h> #include <string.h> int main () { char szMyName [20]; strcpy (szMyName,"J. Soulie"); cout << szMyName; return 0; } J. Soulie

Observe que necesitamos incluir la biblioteca <string.h> para poder usar la funcin strcpy. Aunque podramos escribir una simple funcin como la siguiente: setstring con la misma operacin que la funcin strcpy de la cstring:
// setting value to string #include <iostream.h> void setstring (char szOut [], char szIn []) { int n=0; do { szOut[n] = szIn[n]; } while (szIn[n++] != '\0'); } int main () J. Soulie

{ char szMyName [20]; setstring (szMyName,"J. Soulie"); cout << szMyName; return 0; }

Otro mtodo frecuentemente usado para asignar valores a un arreglo es is usando directamente el stream de entrada (cin). En este caso, el valor de la cadena es asignada por el usuario durante la ejecucin del programa. Cuando cin es usado con cadenas de caracteres, es generalmente usado con su mtodo getline, que puede ser llamado siguiendo este prototipo:
cin.getline ( char buffer[], int length, char delimiter = ' \n');

Donde buffer es la direccin donde se va a almacenar la entrada (como un arreglo, por ejemplo), length es largo mximo de el buffer (el tamao del arreglo) y delimiter es el caracter usado para determinar el final de la entrada, el cual por defecto - si no incluimos dicho parmetro - ser el caracter de fin de lnea ('\n'). El siguiente ejemplo repite lo que escriba en el teclado. Es muy simple pero sirve como un ejemplo de como se puede usar cin.getline con cadenas:
// cin with strings #include <iostream.h> int main () { char mybuffer [100]; cout << "What's your name? "; cin.getline (mybuffer,100); cout << "Hello " << mybuffer << ".\n"; cout << "Which is your favourite team? "; cin.getline (mybuffer,100); cout << "I like " << mybuffer << " too.\n"; return 0; } What's your name? Juan Hello Juan. Which is your favourite team? Inter Milan I like Inter Milan too.

Observe como en ambas llamadas a cin.getline usamos el mismo identificador de cadena (mybuffer). Lo que el programa hace en la segunda llamada es simplemente sobreescribir el contenido previo de buffer con el que ha sido introducido. Si recuerda la seccin sobre comunicacin a travs de la consola, recordar que usamos el operador de extraccin (>>) para recibir data directamente de la entrada estndar. Este mtodo tambin puede ser usado, en vez de cin.getline con cadenas de caracteres. Por

ejemplo, en nuestro programa, cuando solicitamos una entrada del usuario pudimos haber escrito:
cin >> mybuffer;

Esto funcionara, pero este mtodo tiene las siguientes limitaciones que cin.getline no tiene:

Slo puede recibir palabras simples (no oraciones completas) ya que este mdoto usa como delimitador cualquier ocurrencia de un caracter en blanco, incluyendo espacios, tabuladores, fin de lnea y retorno de carro. No permite especificar un tamao para el buffer. Esto hace a sus programas inestables en caso de que la entrada del usuario sea mayor que el arreglo que lo recibir.

Por estas razones es recomendable que cuando requiera cadenas de caracteres provenientes de cin use cin.getline en vez de cin >>.

Convirtiendo cadenas de caracteres a otros tipos


Debido a que una cadena puede contener representaciones de otros tipos de datos, como nmeros, podra ser til traducir ese contenido a una variable de tipo numrica. Por ejemplo, una cadenapuede contener "1977", pero esto es una secuencia de 5 caracteres no tan facilmente convertibles a enteros simples. La biblioteca cstdlib (stdlib.h) provee tres tiles funciones para este propsito:

atoi: convierte string a int type. atol: convierte string a long type. atof: convierte string a float type.

Todas estas funciones admiten un parmetro y retornan un valor del tipo de dato solicitado (int, long o float). Estas funciones combinadas con el mtodo getline de cin son dan una manera ms confiable de leer la entrada del usuario cuando se solicita un nmero, que con el mtodo clsico cin>>:
// cin and ato* functions #include <iostream.h> #include <stdlib.h> int main () { char mybuffer [100]; float price; int quantity; cout << "Enter price: "; cin.getline (mybuffer,100); price = atof (mybuffer); cout << "Enter quantity: "; cin.getline (mybuffer,100); Enter price: 2.75 Enter quantity: 21 Total price: 57.75

quantity = atoi (mybuffer); cout << "Total price: " << price*quantity; return 0; }

Funciones para manipular cadenas de caracteres


La biblioteca cstring (string.h) define muchas funciones para realizar operaciones de manipulacin con cadenas tipo C (como ya se explic con strcpy). Aqu tiene una breve vista de las ms usuales: strcat: char* strcat (char* dest, const char* src); Concatena src al final de dest. Retorna dest. strcmp: int strcmp (const char* string1, const char* string2); Compara las cadenas string1 y string2. Retorna 0 si ambas cadenas son iguales. strcpy: char* strcpy (char* dest, const char* src); Copia el contenido de src a dest. Retorna dest. strlen: size_t strlen (const char* string); Retorna el largo de string. NOTA: char* es lo mismo que char[] Chequee la Referencia C++ para informacin adicional sobre estas y otras funciones de esta biblioteca.

Seccin 3.3

Apuntadores
Ya hemos visto como las variables son celdas de memoria a las que podemos acceder por un identificador. Pero estas variables estn almacenadas en lugares concretos de la memoria del computador. Para nuestros programas, la memoria del computador es solo una sucesin de celdas de 1 byte (el tamao mnimo para un dato), cada una con una nica direccin. Una buena comparacin para la memoria del computador puede ser una calle en una ciudad. En una calle todas las casas estn enumeradas consecutivamente con un identifcador nico as que si hablamos de las 27ava de la calle Sesame seremos capaces de encontrar ese lugar sin problemas, ya que debe haber solo una casa con ese nmero, y adems sabemos que esa casa estar entre las casas 26 y 28. De la misma manera en que las casas en una calle estn numeradas, el sistema operativo organiza la memoria con nmeros meros nicos y consecutivos, as que si hablamos de la localidad 1776 en la memoria, sabemos que hay solo una localidad con esa direccin y tambin que est entre las direcciones 1775 y 1777.

Operador de (derefencia) de direcciones (&).


En el momento en que declaramos una variable, sta debe ser almacena en una localidad concreta en esta sucesin de celdas (la memoria). Generalmente no decidimos donde ser colocada la variable - afortunadamente eso es algo hecho automaticamente hecho por el compilador y el sistema operativo en tiempo de ejecucin -, pero una vez que el sistema operativo ha asignado una direccin hay algunos casos en los que podemos estar interesados en saber donde la variable est almacenada.

Esto puede se puede hacer precediendo el identificador de la variable por un ampersand (&), que significa literalmente "direccin de". Por ejemplo:
ted = &andy;

asignara a la variable ted la direccin de la variable andy, ya que cuando se precede el nombre de la variable andy con el ampersand (&) no estamos hablando del contenido de la variable, sino de su direccin de memoria.

Vamos a suponer que andy ha sido colocado en la direccin de memoria 1776 y que escribimos lo siguiente:
andy = 25; fred = andy; ted = &andy;

El resultado se muestra en el siguiente diagrama:

Hemos asignado a fred el contenido de la variable andy como hemos hecho en muchas otras ocasiones en secciones previas de este tutorial, pero para ted hemos asignado la direccin en memoria donde el sistema operativo almacena el valor de andy, que hemos imaginado que era 1776 (puede ser cualquier direccin, sta es inventada). La razn es que en la asignacin de ted hemos precedido a andy con un ampersand (&).

La variable que almacena la direccin de otra variable (como ted en el ejemplo previo) es lo que llamamos un apuntador. En C++ los apuntadores tienen ciertas virtudes y son usados frecuentemente. Ms adelante veremos como se declara este tipo de variable.

Operador de Referencia (*)


Usando un apuntador podemos acceder directamente al valor almacenado en la variable apuntada por el con tan solo preceder el identificador del apuntador con el operador de referencia asterisk (*), que puede ser literalmente traducido como "valor apuntado por". Por lo tanto, siguiendo con los valores del ejemplo previo, si escribimos:
beth = *ted;

(que podemos leer como: "beth es igual al valor apuntado por ted") beth tomara el valor 25, ya que ted es 1776, y el valor apuntado por 1776 es 25.

Debe diferenciar claramente que ted almacena 1776, pero *ted (con un asterisco * antes) se refiere al valor almacenado en la direccin 1776, que es 25. Note la diferencia entre incluir o no incluir el asterisco (He incluido un comentario explicativo de como cada expresin podra ser leida):
beth = ted; beth = *ted; // beth es igual a ted ( 1776 ) // beth es igual al valor apuntado por ted ( 25 )

Operador de direccin o desreferencia (&) Es usado como un prefijo de variable y puede ser traducido como "direccin de", as: &variable1 puede ser leida como "direccin de variable1"

Operator de referencia (*) Indica que lo que debe ser evaluado es el contenido apuntado por la expresin considerada como una direccin. Puede ser traducido como "valor apuntado por". * mypointer puede ser leido como "valor apuntado por mypointer". En este momento, y siguiendo con el mismo ejemplo iniciado arriba, donde:
andy = 25; ted = &andy;

debera claramente ver que todas las expresiones siguientes son verdaderas:

andy == 25 &andy == 1776 ted == 1776 *ted == 25

La primera expresin es muy clara considerando que su asignacin fue andy=25;. La segunda usa el operador de direccin (o desreferencia) (&) que retorna la direccin de la variable andy, que imaginamos que es 1776. La tercera es muy obvia ya que la segunda fue cierta y la asignacin de ted era ted = &andy;. La cuarta expresin el operador de referencia (*) que, como acabamos de ver, es equivalente al valor contenido en la direccin apuntada por ted, que es 25.

As, despues de todo esto, podra tambin inferir que mientras la direccin apuntada por ted permanezca invariable, la siguiente expresin tambin ser verdadera:
*ted == andy

Declarando variables de tipo apuntador


Debido a la habilidad de un apuntador para referenciar directamente el valor al que apunta, es necesario especificar a que tipo de data apunta un apuntador cuando se declara. No es lo mismo apuntar a un char que apuntar a un int o un float.

Por lo tanto, la declaracin de apuntadores se realiza de esta forma:


type * pointer_name;

donde type es el tipo de data apuntada, no el tipo del apuntador en s. Por ejemplo:
int * number; char * character; float * greatnumber;

son tres declaraciones de apuntadores. Cada una apunta a un tipo de dato diferente, pero los tres son apuntadores y en realidad los tres ocupan la misma cantidad de espacio en memoria (el tamao de un apuntador depende del sistema operativo), pero los datos a los que apuntan no ocupan la misma cantidad de espacio ni son del mismo tipo, uno es int, otro es char y el otro es float.

Enfatizo que el asterisco (*) que usamos cuando declaramos un apuntador significa slo que es un apuntador, y no se debe confundir con el operador de referencia que vimos hace poco, que tambin se escribe con un asterisco (*). Son simplemente dos tareas diferentes representadas con el mismo signo.
// my first pointer #include <iostream.h> int main () value1==10 / value2==20

{ int value1 = 5, value2 = 15; int * mypointer; mypointer = &value1; *mypointer = 10; mypointer = &value2; *mypointer = 20; cout << "value1==" << value1 << "/ value2==" << value2; return 0; }

Note como los valores de value1 y value2 han cambiado indirectamente. Primero hemos asignado a mypointer la direccin de value1 usando el signo de desreferencia (&). Luego hemos asignado 10 al valor apuntado por mypointer, el cual est apuntando a la direccin de value1, por lo que hemos modificado value1 indirectamente.

Para que pueda ver que un apuntador puede tomar varios valores diferentes en el mismo programa hemos repetido el proceso con value2 y el mismo apuntador. Aqu est un ejemplo un poco ms complicado:
// more pointers #include <iostream.h> int main () { int value1 = 5, value2 = 15; int *p1, *p2; p1 = &value1; // p1 = address of value1 p2 = &value2; // p2 = address of value2 *p1 = 10; // value pointed by p1 = 10 *p2 = *p1; // value pointed by p2 = value pointed by p1 p1 = p2; // p1 = p2 (value of pointer copied) *p1 = 20; // value pointed by p1 = 20 cout << "value1==" << value1 << "/ value2==" << value2; return 0; } value1==10 / value2==20

He incluido como comentarios en cada lnea como se puede leer el cdigo: ampersand (&) como "direccin de" y asterisco (*) como "valor apuntado por". Observe que hay

expresiones con apuntadores p1 y p2 con y sin el asterisco. El significado de usar o no un asterisco de referencia es muy diferente: Un asterisco (*) seguido por el apuntador se refiere a el lugar apuntado por el apuntador, en cambio un apuntdor sin un asterisco (*) se refiere al valor del apuntador en si, que es, la direccin de donde est apuntando. Otra cosa que puede llamar su atencin es la lnea:
int *p1, *p2;

que declara los dos apuntadores de el ejemplo previo poniendo un asterisco (*) para cada apuntador. La razn es que el tipo para todas las declaraciones de la misma lnea es int (y no int*). La explicacin es debido al nivel de precedencia del operador de referencia asterisco (*), que es el mismo que en la declaracin de tipos, por lo tanto, ya que son operadores asociativos desde la derecha, los asteriscos son evaluados antes que el tipo. Hemos hablado sobre esto en la seccin 1.3: Operadores, aunque es suficiente que sepa claramente que -a menos que incluya parntesis- tendr que poner un asterisco (*) antes de cada apuntador que declare.

Apuntadores y arreglos
El concepto de arreglo est muy cercano al de apuntador. En realidad, el identificador de un arreglo es equivalente a la direccin de su primer elemento, como un apuntador es equivalente a la direccin del primer elemento al que apunta, as que en realidad son lo mismo. Por ejemplo, suponiendo estas dos declaraciones:
int numbers [20]; int * p;

la siguiente asignacin sera vlida:


p = numbers;

En este momento p y numbers son equivalentes y tienen las mismas propiedades, la nica diferencia es que podramos asignar otro valor al apuntador p mientras que numbers apuntar siempre al primero de los 20 enteros de tipo int con el que fue definido. As, a diferencia de p, que es un apuntador variable ordinario, numbers es un apuntador constante (en realidad el nombre de un arreglo es un apuntador constante). Por lo tanto, aunque la expresin previa fue vlida, la siguiente asignacin no lo es:
numbers = p;

porque numbers es un arreglo (apuntador constante), y no se pueden asignar valores a identificadores constantes.

Debido a su naturaleza de variables todas las expresiones que incluyen apuntadores en el siguiente ejemplo son perfectamente vlidas:

// more pointers #include <iostream.h> int main () { int numbers[5]; int * p; p = numbers; *p = 10; p++; *p = 20; p = &numbers[2]; *p = 30; p = numbers + 3; *p = 40; p = numbers; *(p+4) = 50; for (int n=0; n<5; n++) cout << numbers[n] << ", "; return 0; }

10, 20, 30, 40, 50,

En el captulo "Arreglos" usamos corchetes [] muchas veces para especificar el ndice del elemento del arreglo al que queremos referenciar. Bien, el operador corchetes [] es conocido como operador de offset y es equivalente a aadir el nmero dentro de parntesis a la direccin de un apuntador. Por ejemplo, ambas expresiones son vlidas:
a[5] = 0; *(a+5) = 0; // a [offset of 5] = 0 // pointed by (a+5) = 0 son equivalentes y vlidas tanto si a es un apuntador como si es un arreglo.

Inicializacin de Apuntadores
Cuando declaramos apuntadores podemos querer especificar explcitamente a que variable queremos que apunten,
int number; int *tommy = &number;

esto es equivalente a:
int number; int *tommy; tommy = &number;

Cuando se produce una asignacin de apuntador siempre estamos asignando la direccin a la que apunta, nunca el valor apuntado. Debe considerar que al momento de declarar un apuntador, el asterisco (*) indica slo que es un apuntador, en ningn caso indica el oparador de referencia (*). Recuerde, son dos operadores diferentes, aunque se escriban con el mismo signo. As, debemos tener cuidado de no confundir lo anterior con:
int number; int *tommy; *tommy = &number;

que de cualquier manera no tendr mucho sentido en este caso.

Como en el caso de los arreglos, el compilador permite el caso especial de que queramos inicializar el contenido al cual el contenido apunta con constantes al mismo momento de declarar el apuntador:
char * terry = "hello";

en este caso se reserva memoria esttica para contener "hello" y un apuntador al primer char de este bloque de memoria (que corresponde a 'h') se asigna a terry. Si imaginamos que "hello" es almacenado en las direcciones 1702 y siguientes, la declaracin previa puede ser bosquejada as:

es importante indicar que terry contiene el valor 1702 y no 'h' ni "hello", aunque 1702 apunte a estos caracteres.

El apuntador terry apunta a una cadena de caracteres y puede ser usado exactamente como si fuera un arreglo (recuerde que un arreglo es solo un apuntador constante). Por ejemplo, si nuestro temperamento cambi y quisimos reemplazar la 'o' por un '!' en el contenido apuntado por terry, podramos hacerlo por cualquiera de estas dos maneras:
terry[4] = '!'; *(terry+4) = '!';

recuerde que escribir terry[4] es lo mismo que escribir *(terry+4), aunque la expresin ms usual es la primera. COn cualquiera de estas dos expresiones pasara algo como esto:

Aritmtica de apuntadores
Realizar operaciones aritmticas sobre apuntadores es un poco diferente a realizarlas sobre otros tipos de datos enteros. Para empezar, slo se permiten realizar operaciones de adicin y

substraccin, las otras no tienen sentido en el mundo de los apuntadores. Pero ambas (la adicin y substraccin) tienen un comportamiento diferente con los apuntadores de acuerdo al tamao del tipo de dato al cual apuntan.

Cuando vimos los diferentes tipos de dato que existen, vimos que algunos ocupan ms o menos espacio que otros en memoria. Por ejemplo, en el caso de nmeros enteros, char ocupa 1 byte, short ocupa 2 bytes y long ocupa 4. Supongamos que tenemos 3 apuntadores:
char *mychar; short *myshort; long *mylong;

y que sabemos que aputan a las direcciones de memoria 1000, 2000 y 3000 respectivamente.

As que si escribimos:
mychar++; myshort++; mylong++; mychar, como se podra esperar, contendra el valor 1001. Sin embargo, myshort contendra el

valor 2002, y mylong contendra 3004. La razn es que cuando sumamos 1 a un apuntador estamos haciendo que apunte al siguiente elemento del mismo tipo con el cual ha sido definido, y por lo tanto el tamao en bytes del tipo tipo apuntado es aadida al apuntador.

Esto es aplicable tanto cuando se suma como cuando se resta cualquier nmero a un apuntador. Pasara exactamente lo mismo si escribimos:
mychar = mychar + 1; myshort = myshort + 1; mylong = mylong + 1;

Es importante advertirle que los operadores de incremento (++) y decrecemento (--) tienen mayor prioridad que el operador de referencia asterisco (*), por lo tanto las siguientes expresiones pueden llevar a confusin:
*p++; *p++ = *q++;

La primera es equivalente a *(p++) y lo que hace es incrementar p (la direccin a donde apunta no el valor que contiene). En la segunda, ya que ambos operadores de incremento (++) estn despus de las expresiones a ser evaluadas y no antes, primero el valor de *q es asignado a *p y luego ambos, q y p son incrementados en uno. Es equivalente a:
*p = *q; p++; q++;

Como siempre, recomiendo usar parntesis () para evitar resultados inesperados.

Apuntadores a apuntadores
C++ permite el uso de apuntadores que apuntan a apuntadores, que stos, en su momento, apuntan a datos. Para hacer esto slamente necesitamos agregar un asterisco (*) por cada nivel de referencia:
char a; char * b; char ** c; a = 'z'; b = &a; c = &b;

esto, suponiendo las localidades de memoria 7230, 8092 y 10502, escogidas aleatoriamente, podra ser descrito as:

(adentro de las celdas se encuentra el contenido de la variable; debajo de la celda, su localidad)

Lo nuevo en este ejemplo es la variable c, de la cual podemos hablar de tres diferentes maneras, cada una de ellas correspondiendo a un valor diferente:

c es una variable de tipo (char **) con un valor de 8092 *c es una variable de tipo (char*) con un valor de 7230 **c es una variable de tipo (char) con un valor de 'z'

Apuntadores void (vacos)


El tipo de apuntador void es un tipo especial de apntador. Apuntadores void pueden apuntar a cualquier tipo de dato, desde un valor entero o flotante a una cadena de caracteres. Su nica limitacin es que el dato apuntado no puede ser referenciado directamente (no podemos usar el operador de referencia *), ya que su tamao es siempre indetermindo, y por esa razn siempre tenemos que recurrir a type casting o asignaciones para hacer que nuestro apuntador void apunte a un tipo de dato contreto al cual podamos referenciar.

Una de sus utilidades puede ser para pasar parmetros genricos a una funcin:
// integer increaser #include <iostream.h> void increase (void* data, int type) { switch (type) { case sizeof(char) : (*((char*)data))++; break; case sizeof(short): (*((short*)data))++; break; case sizeof(long) : (*((long*)data))++; break; } } int main () { char a = 5; short b = 9; long c = 12; increase (&a,sizeof(a)); increase (&b,sizeof(b)); increase (&c,sizeof(c)); cout << (int) a << ", " << b << ", " << c; return 0; } sizeof es un operador integrado en el lenguaje C++ que retorna un valor constante con el 6, 10, 13

tamao en bytes de su parmetro, por ejemplo, sizeof(char) es 1, porque el tipo char es de 1 byte.

Apuntadores a funciones

C++ permite operacioens con apuntadores a funciones. El mayor uso de esto es para pasar una funcin como un parmetro a otra funcin, ya que stas no pueden ser pasadas desreferenciadas. Para declarar un apuntador a una funcin debemos declararlo como el prototipo de la funcin excepto que el nombre de la funcin est encerrada entre parntesis () y que se inserta un asterisco (*) antes del nombre. Puede que no sea una sintaxis muy manejable, pero as es como se hace en C++:
// pointer to functions #include <iostream.h> int addition (int a, int b) { return (a+b); } int subtraction (int a, int b) { return (a-b); } int (*minus)(int,int) = subtraction; int operation (int x, int y, int (*functocall)(int,int)) { int g; g = (*functocall)(x,y); return (g); } int main () { int m,n; m = operation (7, 5, addition); n = operation (20, m, minus); cout <<n; return 0; } 8

En el ejemplo, minus es un apuntador global a una funcin que tiene dos parmetros de tipo int, es immediatamente asignado a apuntar a la funcin subtraction, todo en una sola lnea:
int (* minus)(int,int) = subtraction;

Seccin 3.4

Memoria Dinmica
Hasta ahora, en nuestros programas, tenemos tanta memoria como pedimos en las declaraciones de variables, arreglos y otros objetos que incluimos, teniendo el tamao de todos ellos fijo antes de la ejecucin del programa. Pero, que tal si necesitamos una cantidad variable de memoria que slo puede ser determinada durante la ejecucin del

programa (runtime), por ejemplo, en caso de que necesitemos una entrada del usuario para determinar la cantidad de espacio necesaria? La respuesta es memoria dinmica, para la cual C++ integra los operadores new y delete.
Operadores new y delete son exclusivos de C++. Ms adelante en esta seccin se muestran los equivalentes en C para estos operadores.

Operadores new y new[ ] Para solicitar memoria dinmica, existe el operador new. new es seguido por un tipo de dato y opcionalmente el nmero de elementos requeridos entre corchetes []. Retorna un apuntador al comienzo del nuevo bloque de memoria asignada. Su forma es:
pointer = new type

o
pointer = new type [elementos]

La primera expresin es usada para asignar memoria para contener un solo elemento detipo type. La segunda se usa para asignar un bloque (un arreglo) de elementos de tipo type. Por ejemplo:
int * bobby; bobby = new int [5];

En este caso, el sistema operativo ha asignado espacio para 5 elementos de tipo int en un heap y ha retornado un apuntador a su comienzo que ha sido asignado a bobby. Por lo tanto, ahora, bobby apunta a un bloque de memoria vlido con espacio para 5 elementos int.

Podra preguntarse cual es la diferencia entre declarar un arreglo normal y asignar memoria a un apuntador como hemos hecho. La ms importante es que el tamao de un arreglo debe ser un valor constante, el cual limita su tamao a lo que decidamos al momento de designar el programa antes de su ejecucin, mientra que la asignacin dinmica de memoria permite asignar memoria durante la ejecucin del programa usando cualquier variable, constante o combinacin de ambas como tamao.

La memoria dinmica es generalmente administrada por el sistema operativo, y en interfaces multitarea puede ser compartida entre varias aplicaciones, por lo que existe la posibilidad de que la memoria se acabe. Si esto ocurre y el sistema operativo no puede

asignar la memoria que solicitamos con el operador new, se retorna un apuntador nulo. Por esta razn se recomienda siempre chequear si el apuntador retornado es nulo, luego de una llamada a new.
int * bobby; bobby = new int [5]; if (bobby == NULL) { // error asignando memoria. Tome medidas. };

Operador delete Ya que la necesidad de memoria dinmica est limitada a momentos concretos dentro de un programa, una vez que no se necesita ms debera ser liberada para que se convierta en disponible para futuras solicitudes de memoria dinmica. Para este propsito existe el operador delete, cuya forma es:
delete pointer;

o
delete [] pointer;

La primera expresin debera ser utilizada para borrar memoria asignada para un nico elemento, y la segunda para memoria asignada para mltiples elementos (arreglos). En la mayora de los compiladores ambas expresiones son equivalentes y pueden ser utilizadas sin distincin, aunque en realidad son dos operadores diferentes y as deben ser considerados para sobrecarga de operadores (veremos eso en la seccin 4.2).
// rememb-o-matic #include <iostream.h> #include <stdlib.h> int main () { char input [100]; int i,n; long * l; cout << "How many numbers do you want to type in? "; cin.getline (input,100); i=atoi (input); l= new long[i]; if (l == NULL) exit (1); for (n=0; n<i; n++) { cout << "Enter number: "; cin.getline (input,100); l[n]=atol (input); } cout << "You have entered: "; How many numbers do you want to type in? 5 Enter number : 75 Enter number : 436 Enter number : 1067 Enter number : 8 Enter number : 32 You have entered: 75, 436, 1067, 8, 32,

for (n=0; n<i; n++) cout << l[n] << ", "; delete[] l; return 0; }

Este simple ejemplo que memoriza nmeros no tiene una cantidad limitada de nmeros que pueden ser introducidos, gracias ya que solicitamos al sistema proveernos de tanto espacio como sea necesario para almacenar todos los nmeros que el usuario desee intruducir.
NULL

es un valor constante definido en varias bibliotecas C++ especialmente diseado para indicar apuntadores nulos. En caso de que esta constante no est definida puede hacerlo usted mismo definiendola a 0:
#define NULL 0

Es indiferente poner 0 o NULL cuando se chequean apuntadores, pero el uso de NULL con apuntadores es ampliamente extendido y es recomendado para mayor legibilidad. La razn es que un apuntador es raramente comparado o fijado directamente a una constante numrica excepto precisamente el nmero 0, y de esta manera esta accin es enmascarada simblicamente.

Memoria dinmica en ANSI-C


Los operadores new y delete son exclusivos de C++ y no estn disponibles en lenguaje C. En C, para asignar memoria dinmica tenemos que recurrir a la biblioteca stdlib.h. Las vamos a ver, ya que tambin son vlidas en C++ y son usadas en algunos programas existentes.

La funcin malloc Es la funcin genrica para asignar memoria dinmica a apuntadores. Su prototipo es:
void * malloc (size_t nbytes);

donde nbytes es el nmero de bytes que queremos que sean asignados al apuntador. La funcin retorna un apuntador de tipo void*, por lo que tenemos que hacer type cast al valor al tipo del apuntador destino, por ejemplo:
char * ronny; ronny = (char *) malloc (10);

Esto asigna a ronny un apuntador a un bloque de 10 bytes. Cuando queremos asignar un bloque de data a un tipo diferente a char (diferente a 1 byte) debemos multiplicar el nmero de elementos deseados por el tamao de cada elemento. afortunadamente tenemos a nuestra disposicin el operador sizeof, que retorna el tamao del tipo de un dato en concreto.
int * bobby; bobby = (int *) malloc (5 * sizeof(int));

Este cdigo asigna a bobby un apuntador a un bloque de 5 enteros de tipo int, este tamao puede ser igual a 2, 4 o ms bytes de acuerdo al sistema donde el programa es compilado.

La funcin calloc calloc es muy similar a malloc en su funcionamiento, su principal diferencia es en su prototipo:
void * calloc (size_t nelements, size_t size);

ya que admite 2 parmetros en vez de 1. Estos dos parmetros se multiplican para obtener el tamao total del bloque de memoria a ser asignado. Usualmente el primer parmetros (nelements) es el nmero de elementos y el segundo (size) sirve para especificar el tamao de cada elemento. Por ejemplo, podramos definir a bobby con calloc as:
int * bobby; bobby = (int *) calloc (5, sizeof(int));

Otra diferencia entre malloc y calloc es que calloc inicializa todos sus elementos a 0.

La funcin realloc Cambia el tamao de un bloque de memoria ya asignado a un apuntador.


void * realloc (void * pointer, size_t size);

El parmetro pointer recibe un apuntador a un bloque de memoria ya asignado o un apuntador nulo, y size especifica el nuevo tamao que el bloque de memoria deber tener. La funcin asigna size bytes de memoria al apuntador. La funcin podra necesitar cambiar la localidad del bloque de memoria para que el nuevo tamao pueda encajar, en ese caso el contenido actual del bloque es copiado al nuevo para garantizar que la data existente no se pierda. La funcin retorna el nuevo apuntador. Si no ha sido posible asignar el bloque de memoria con el nuevo tamao retorna un apuntador nulo, pero el pointer especificado como parmetro y su contenido permanecen sin cambios.

La funcin free Libera un bloque de memoria dinmica previamente asignado usando malloc, calloc o realloc.
void free (void * pointer);

Esta funcin debe ser usada solamente para liberar memoria asignada con las funciones malloc, calloc y realloc.

Puede obtener ms informacin acerca de estas funciones en la referencia C++ para cstdlib.

Seccin 3.5

Estructuras

Estructuras de datos
Una estructura de datos es un conjunto de diversos tipos de datos que pueden tener diferentes tamaos agrupados bajo una nica declaracin. Su forma es la siguiente:
struct model_name { type1 element1; type2 element2; type3 element3; . . } object_name; donde model_name es un nombre para el modelo de el tipo de estructura y el parmetro opcional object_name es un identificador (o identificadores) vlido para instanciarlos. Entre llaves { }

estn los tipos y sus sub-identificadores correspondientes a los elementos que componen la estructura.

Si la definicin de la estructura incluye el parmetro model_name (opcional), ese parmetro se convierte en un nombre de tipo vlido equivalente a la estructura. Por ejemplo:
struct producto { char nombre [30]; float precio; } ; producto manzana; producto naranja, melon;

Hemos primero definido el modelo de la estructura producto con dos campos: nombre y precio, cada uno de un tipo diferente. Luego hemos usado el nombre del tipo de estructura (producto) para declarar tres objetos de ese tipo: manzana, naranja y melon.

Una vez declarado, producto se ha convertido en un nuevo nombre de tipo vlido como los fundamentales int, char o short y podemos declarar objetos (variables) de ese tipo. El campo opcional object_name que puede ir al final de la declaracin de la estructura sirve para declarar directamente objetos del tipo de la estructura. Por ejemplo, podemos tambin declarar los objetos manzana, naranja y melon de esta manera:
struct producto { char nombre [30]; float precio; } manzana, naranja, melon;

Adems, en casos como el ltimo en el cual utilizamos el modelo de la estructura para declarar objetos de ella, el parmetro model_name (en este caso producto) es opcional. Aunque si model_name no se incluye no ser posible declarar mas objetos de este mismo modelo despus.

Es importante direneciar claramente entre lo que es un modelo de estructura, y lo que es un objeto de estructura. Usando los trminos que usamos con variables, el modelo es el tipo, y el objeto es la variable. podemos instanciar muchos objetos (variables) de un nico model (tipo). Una vez que hemos declarado nuestros tres objetos de un determinado modelo de estructura (manzana, naranja y melon) podemos operar con los campos que los forman. Para hacerlo tenemos que usar un punto (.) insertado entre el nombre del objeto y el nombre del campo. Por ejemplo, podramos operar con cualquiera de estos elementos como si fueran variables estandares de sus respectivos tipos:
manzana.nombre manzana.precio naranja.nombre naranja.precio melon.nombre melon.precio

Cada uno siendo de su correspondiente tipo de dato: manzana.nombre, naranja.nombre y melon.nombre son de tipo char[30], y manzana.precio, naranja.precio and melon.precio son de tipo float.

Vamos a dejar las manzanas, naranjas y melones y seguiremos con un ejemplo sobre pelculas:
// example about structures #include <iostream.h> #include <string.h> #include <stdlib.h> struct movies_t { char title [50]; int year; } mine, yours; void printmovie (movies_t movie); int main () { char buffer [50]; strcpy (mine.title, "2001 A Space Odyssey"); mine.year = 1968; Enter title: Alien Enter year: 1979 My favourite movie is: 2001 A Space Odyssey (1968) And yours: Alien (1979)

cout << "Enter title: "; cin.getline (yours.title,50); cout << "Enter year: "; cin.getline (buffer,50); yours.year = atoi (buffer); cout << "My favourite movie is:\n "; printmovie (mine); cout << "And yours:\n "; printmovie (yours); return 0; } void printmovie (movies_t movie) { cout << movie.title; cout << " (" << movie.year << ")\n"; }

El ejemplo muestra como podemos utilizar los elementos de una estructura y la misma estructura como variables normales. Por ejemplo, yours.year es una variable vlida de tipo int, y mine.title es un arreglo vlido de 50 chars. Observe que mine y yours son tambin tratadas como variables vlidas de tipo movies_t cuando son pasadas a la funcin printmovie(). Por lo tanto, una de las ventajas ms importantes de las estructuras es que podemos referenciar tanto a sus elementos individualmente o a la estructura entera como un bloque. Las estructuras son utilizadas muy frecuentemente para construir bases de datos, especialmente si consideramos la posibilidad de construir arreglos de ellas.
// array of structures #include <iostream.h> #include <stdlib.h> #define N_MOVIES 5 struct movies_t { char title [50]; int year; } films [N_MOVIES]; void printmovie (movies_t movie); int main () { char buffer [50]; int n; Enter Enter Enter Enter Enter Enter Enter Enter Enter Enter title: Alien year: 1979 title: Blade Runner year: 1982 title: Matrix year: 1999 title: Rear Window year: 1954 title: Taxi Driver year: 1975

You have entered these movies: Alien (1979) Blade Runner (1982) Matrix (1999)

for (n=0; n<N_MOVIES; n++) { cout << "Enter title: "; cin.getline (films[n].title,50); cout << "Enter year: "; cin.getline (buffer,50); films[n].year = atoi (buffer); } cout << "\nYou have entered these movies:\n"; for (n=0; n<N_MOVIES; n++) printmovie (films[n]); return 0; } void printmovie (movies_t movie) { cout << movie.title; cout << " (" << movie.year << ")\n"; }

Rear Window (1954) Taxi Driver (1975)

Apuntadores a estructuras
Como cualquier otro tipo, las estructuras pueden ser apuntadas por apuntadores. Las reglas son las mismas que para cualquier tipo de dato fundamental: El apuntador debe ser declarado como un apuntador a la estructura:
struct movies_t { char title [50]; int year; }; movies_t amovie; movies_t * pmovie; Aqu amovie es un objeto de tipo movies_t y pmovie es un apuntador para apuntar a objetos de

tipo movies_t. As que lo siguiente, como con los tipos fundamentales, tambin sera vlido:
pmovie = &amovie;

Ok, continuemos con otro ejemplo, que servir para introducir un nuevo operador:
// pointers to structures #include <iostream.h> #include <stdlib.h> struct movies_t { char title [50]; int year; Enter title: Matrix Enter year: 1999 You have entered: Matrix (1999)

}; int main () { char buffer[50]; movies_t amovie; movies_t * pmovie; pmovie = & amovie; cout << "Enter title: "; cin.getline (pmovie->title,50); cout << "Enter year: "; cin.getline (buffer,50); pmovie->year = atoi (buffer); cout << "\nYou have entered:\n"; cout << pmovie->title; cout << " (" << pmovie->year << ")\n"; return 0; }

El cdigo anterior incluye una introduccin importante: el operador ->. Este es un operador de referencia que es usado exclusivamente con apuntadores a estructuras y apuntadores a clases. Nos permite no tener que usar parentesis en cada referencia a un miembro de una estructura. En el ejemplo utilizamos:
pmovie->title

que se puede traducir como:


(*pmovie).title

ambas expresiones pmovie->title y (*pmovie).title son vlidas y significan que estamos evaluando el elemento title de la estructura apuntada por pmovie. Debe distinguirlo claramente de:
*pmovie.title

que es equivalente a
*(pmovie.title)

y que servira para evaluar el valor apuntado por el elemento title de la estructura movies, que en este caso (donde title no es un apuntador) no tendra mucho sentido. La siguiente tabla resume las posibles combinaciones de apuntadores y estructuras:

Expresin
pmovie.title

Descripcin Elemento title de la estructura pmovie

Equivalente

pmovie->title Elemento title de la estructura apuntada por pmovie

(*pmovie).title

*pmovie.title

Valor apuntado por el elemento title de la estructura


pmovie

*(pmovie.title)

Anidando Estructuras
Las Estructuras tambin pueden ser anidadas tal que un elemento vlido de una estructura puede ser otra estructura.
struct movies_t { char title [50]; int year; } struct friends_t { char name [50]; char email [50]; movies_t favourite_movie; } charlie, maria; friends_t * pfriends = &charlie;

Por lo tanto, luego de la declaracin previa podramos usar las siguientes expresiones:
charlie.name maria.favourite_movie.title charlie.favourite_movie.year pfriends->favourite_movie.year

(donde, las dos ltimas expresiones son equivalentes).

El concepto de estructuras que ha sido discutido en esta seccin es el mismo usado en lenguaje C, sin embargo, en C++, el concepto de estructuras ha sido extendido hasta la misma funcionalidad de una clase con la peculiaridad de que todos sus elementos son considerados pblicos. Pero tendr ms detalles sobre este tpico en la seccin 4.1, Clases.

Seccin 3.6

Tipos de datos definidos por el Usuario

Ya hemos visto un tipo de dato que es definido por el usuario (programador): Las estructuras. Pero en adicin a estos hay otros tipos de datos definidos por el usuario:

Definicin de tipos propios (typedef)


C++ nos permite definir nuestros propios tipos basados en otros tipos de datos existentes. Para hacer esto usaremos la palabra reservada typedef, cuya forma es:
typedef tipo_existente nuevo_tipo ;

donde tipo_existente es un tipo fundamental de C++ o cualquier otro tipo definido y nuevo_tipo es el nombre que el nuevo tipo que vamos a definir recibir. Por ejemplo:
typedef typedef typedef typedef char C; unsigned int WORD; char * string_t; char field [50];

En este caso hemos definido cuatro nuevos tipos de datos: C, WORD, string_t y field como char, unsigned int, char* y char[50] respectivamente, que podramos perfectamente usar luego como tipos vlidos:
C achar, anotherchar, *ptchar1; WORD myword; string_t ptchar2; field name; typedef puede ser til para definir un tipo que es usado repetidamente dentro de un programa y

es posible que necesitemos cambiarlo en una versin posterior, o si un tipo que quiere usar tiene un nombre muy largo y desea que sea ms corto.

Uniones (Union)
Las Uniones permiten acceder a una porcin de memoria como tipos de datos diferentes, ya que todos estn en realidad en la misma direccin de memoria. Su declaracin y uso es similar a la de las estructuras pero su funcionalidad es totalmente diferente:
union model_name { type1 element1; type2 element2; type3 element3; . . } object_name;

Todos los elementos de la declaracin de la union ocupan el mismo espacio de memoria. Su tamao es el del elemento ms grande de la declaracin. Por ejemplo:
union mytypes_t {

char c; int i; float f; } mytypes;

define tres elementos:


mytypes.c mytypes.i mytypes.f

cada uno de un tipo de dato diferente. Ya que todos se refieren a la misma direccin en memoria, la modificacin de uno de los elementos afectar el valor de todos.

Uno de los usos que una union puede tener es unir un tipo elemental con un arreglo o estructuras de elementos ms pequeos. Por ejemplo,
union mix_t{ long l; struct { short hi; short lo; } s; char c[4]; } mix;

define tres nombres que nos permiten acceder al mismo grupo de 4 bytes: mix.l, mix.s y mix.c y el cual podemos usar de acuerdo a como queramos accesarlo, como long, short o char respectivamente. He mezclado tipos, arreglos y estructuras en la union para que pueda ver las diferentes maneras en que podemos acceder a la data:

Uniones annimas
En C++ tenemos la opcin de que las uniones sean annimas. Si incluimos una unin en una estructura sin ningn nombre de objeto (el que va despues de las llaves { }) la unin ser annima y podremos acceder a los elementos directamente por su nombre. Por ejemplo, observe la diferencia entre estas dos declaraciones: unin
struct {

unin annima
struct {

char title[50]; char author[50]; union { float dollars; int yens; } price; } book;

char title[50]; char author[50]; union { float dollars; int yens; }; } book;

La nica diferencia entre los dos cdigos es que en el primero le dimos un nombre a la unin (price) y en el segundo no. La diferencia es cuando se accede a los miembros dollars y yens de un objeto. En el primer caso sera:
book.price.dollars book.price.yens

whereas in the second it would be:


book.dollars book.yens

Una vez ms le recuerdo que ya que es una unin, los campos dollars y yens ocupan el mismo espacio en la memoria y por lo tanto no pueden ser usados para almacenar valores diferentes. Esto significa que puede incluir un precio en dolares o yens, pero no ambos.

Enumeraciones (enum)
Las enumeraciones sirven para crear tipos de datos para contener algo diferente que no est limitado a constantes numricas o de caracteres o a las constantes true y false. Su forma es la siguiente:
enum model_name { value1, value2, value3, . . } object_name;

Por ejemplo, podramos crear un nuevo tipo de variable llamada color para almacenar colores con la siguiente declaracin:
enum colors_t {black, blue, green, cyan, red, purple, yellow, white};

Observe que no incluimos ning tipo de dato fundamental en la declaracin. Por decirlo de otra manera, hemos creado un nuevo tipo de dato sin que est basado en ninguno existente: el tipo color_t, cuyos posibles valores son los colores que hemos encerrado entre llaves {}. Por ejemplo, una vez declarado colors_t las siguientes expresiones sern vlidas:

colors_t mycolor; mycolor = blue; if (mycolor == green) mycolor = red;

En realidad nuestro tipo de dato enumerado es compilado como un entero y sus posibles valores son cualquier tipo de constante entera especificada. Si no se especifica, el valor entero equivalente al primer valor posible es 0 y los siguientes siguen una progresin +1. As, en nuestro tipo de dato colors_t que definimos antes, black sera equivalente a 0, blue sera equivalente a 1, green a 2 y as sucesivamente.

Si especificamos de manera explcita un valor entero para algunos de los posibles valores de nuestro tipo enumerado (por ejemplo el primero) los siguientes valores sern los incrementos de este, por ejemplo:
enum months_t { january=1, february, march, april, may, june, july, august, september, october, november, december} y2k; en este caso, la variable y2k del tipo enumerado months_t puede contener cualquiera de los 12

posibles valores que van desde january hasta december y que son equivalentes a los valores entre 1 y 12, no entre 0 y 11 ya que hemos hecho january igual a 1.

Seccin 4.1

Clases
Una clase es un metodo logico para organizar datos y funciones en una misma estuctura. Ellas se declaran usando la palabra reservada class, cuya funcionalidad es similar a la de la palabra reservada de C struct, pero con la posibilidad de incluir funciones como miembros, en vez de solo la data. Su forma es:
class class_name { permission_label_1: member1; permission_label_2: member2; ... } object_name;

donde class_name es una nombre para la clase (tipo definido por el usuario) y el campo opcional nombre del objeto object_name para uno o varios identificadores validos de objeto. El cuerpo de la declaracion puede contener members, que pueden ser tanto datos o declaraciones de funciones, y opcionalmente etiquetas de permisologia permission labels, que pueden ser cualquiera de estas tres palabras reservadas: private:, public: o protected:. Ellas hacen referencia a la permisologia la cual los siguientes miembros adquieren:

private

miembros de la clase que son accesibles solo por otro miembro de su misma clase o de sus clases amigas "friend". protected miembros accesibles para miembros de su misma clase y clases amigas friend, y tambien por miembros de sus clases derivadas. Finalmente, public miembros accesibles y visibles desde cualquier sitio.

Si declaramos miembros de una clase antesde incluir cualquier una etiqueta de permisologia, el miembro es considerado private, ya que es la permisologia por defecto que los miembros de una clase declarada con la palabra reservada class adquieren. Por ejemplo:
class CRectangle { int x, y; public: void set_values (int,int); int area (void); } rect;

Declara la clase CRectangle y un objeto llamado rect de esta clase (tipo). Esta clase contiene cuatro miembros: dos variables de tipo int (x y y) en la seccion private (por que private es la permisologia por defecto) y dos funciones en la seccion publica public seccion: set_values() y area(), de las cuales solo incluimos sus prototipos. Note la diferencia entre nombre de clase y nombre de objeto: En el ejemplo anterior, CRectangle era el nombre de la clase (i.e., el tipo definido por el usuario), mientras que rect era un obeto de tipo CRectangle. Es la misma diferencia que int y a tienen en la siguiente declaracion:
int a; int

es el nombre de la clase (tipo) y a es el nombre del objeto (variable).

En instrucciones sucesivas en el cuerpo del programa podemos referir a cualquier miembro publico del objeto rect como si fueran funciones normales o variables, solo poniendo el nombre del objeto seguido por un punto (operador de acceso) y luego el miembro de la clase (como hicimos con las structs de C). por ejemplo:
rect.set_value (3,4); myarea = rect.area();

pero no podriamos referir a x o y ya que son miembros privados de la clase y ellos pueden ser referidos unicamente por otros miembros de la misma clase. Confundido? Aqui esta un ejemplo completo de la clase CRectangle:
// classes example #include <iostream> using namespace std; class CRectangle { int x, y; public: area: 12

void set_values (int,int); int area (void) {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; } int main () { CRectangle rect; rect.set_values (3,4); cout << "area: " << rect.area(); }

Lo nuevo en este codigo es el operador de ambito :: incluido en la definicion de set_values(). Este es usado para declarar un miembro de una clase fuera de ella. Note que hemos definido el procedimiento de la funcion area() dentro de la definicion de la clase CRectangle - dada su extrema simplicidad. mientras que set_values() tiene declarado solo su prototipo dentro de la clase pero su definocion esta afuera. En esta declaracion por fuera debemos usar el operador de ambito ::. El operador de ambito (::) especifica la clase a la cual el miembro que sera declarado pertenece, garantizando exactamente las mismas propiedades de ambito que si hubiera sido declarado dentro de la clase. Por ejemplo, en la funcion set_values() del codigo previo, hemos referido a las variables x y y, que son miembros de la clase CRectangle y ellos son visibles dentro de ella y por sus miembros (ya que son miembros private). La unoca diferencia entre definir una funcion miembro de una clase completamente dentro de una clase e incluir solo su prototipo, es que en el primer caso la funcion automaticamente es considerada inline por el compilador, mientras en la segunda sera una funcion miembro de una clase normal (not-inline). La razon de que hemos hecho x y y miembros private (recuerde que si no hay ninguna otra es decir que todos los miembros de la clase definida con la palabra reservada class tendran acceso private) es porque ya hemos definido una funcion para introducir dichos valores en el objeto (set_values()) y ademas el resto del prograa no tiene una manera directa de accesarlos. Quizs en un ejemplo tan simple como este no vea la gran utilidad de proteger estas dos variables, pero en proyectos mas grandes puede ser muy importante que losvalores no puedan ser modificados de una manera inesperada (inesperada desde el punto de vista del objeto). Uno de los grandes ventajas de una clase es que podemos delarar varios objetos diferentes a partir de ella. Por ejemplo, siguiendo con el ejemplo anterior de la clase CRectangle, podriamos haber declarado el obeto rectb en adicion a el objeto rect :

// class example #include <iostream> using namespace std; class CRectangle { int x, y; public: void set_values (int,int); int area (void) {return (x*y);} }; void CRectangle::set_values (int a, int b) { x = a; y = b; } int main () { CRectangle rect, rectb; rect.set_values (3,4); rectb.set_values (5,6); cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; }

rect area: 12 rectb area: 30

Note que la llamada a rect.area() no da el mismo resultado que la llamada a rectb.area(). esto es porque cada objeto de la clase CRectangle tiene su propias variables x y y, y sus propias funciones set_value() y area(). En esto esta basado el concepto def objeto y programacin orientada a objetos. En esa data y funciones estan las propiedades del objeto, a pesar de la vision usual de objetos como parametros de funciones en programacin estructurada. En esta y en las siguientes secciones discutiremos las ventajas de esta metodologia. En este caso concreto, la clase (tipo de objeto) de la que estamos hablando es CRectangle, de la cual hay dos instancias, u objetos: rect y rectb, cada uno con sus propias variables miembro y funciones miembro.

Constructores y destructores
los objetos generalmente necesitan inicializar variables o asignar memoria dinamica durante sus procesos de creacion para tornarse totalmente operativos y evitar retornar valores inesperados durante su ejecucion. Por ejemplo, que pasaria si en el ejemplo previo llamamos a la funcion area() antes de haber llamado a la funcion set_values? Probablemente un valor indeterminado resultadra ya que los miembros x y y podrian nunca habrseles asignado un valor.

En orden de evitar esto, una clase puede incluir una funcion especial: un constructor, el cual puede ser declarado llamando a una funcion miembro con el mismo nombre de la clase. Esta funcion constructor sera automaticamente llamada cuando una nueva instancia de la clase sea creada (cuando se esta declarando o alocalizando un objeto de esa clase) y solo en ese momento. Vamos a implementar CRectangle incuyendo un constructor:
// classes example #include <iostream> using namespace std; class CRectangle { int width, height; public: CRectangle (int,int); int area (void) {return (width*height);} }; CRectangle::CRectangle (int a, int b) { width = a; height = b; } int main () { CRectangle rect (3,4); CRectangle rectb (5,6); cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; } rect area: 12 rectb area: 30

Como puede ver, el resultado de este ejemplo es identico al previo. En este caso solo hemos reemplazado la funcion set_values, que deja de existir, por un constructor de clase. Note la manera en la cual son pasados los parametros al constructor al momento que las instancias de la clase son creadas:
CRectangle rect (3,4); CRectangle rectb (5,6);

Puede ver tambien como ninguno de los prototipos ni la declaracion del constructor anterior incluyen un valor de retorno, igual que el tipo void. Esto siempre debe ser de esta manera. Un constructor nunca retorna un valor ni tiene que ser especificadoe void, asi como lo hemos presentado en el ejemplo anterior. El Destructor cumple la funcionalidad inversa. Este es automaticamente llamado cuando un objeto es liberado de la memoria, ya sea que su ambito de existencia culmine (por ejemplo, si esta definido como un objeto local dentro de una funcion y la funcion termina) o porque es un objeto dinamicamente asignado y sea liberado usando el operador delete.

El destuctor debe tener el mismo nombre de la clase con una tilde (~) como prefijo y no debe tener valor de retorno. El uso de destructores es especialmente adecuado cuando un objeto asigna memoria dinamica durante su vida y al momento de comenzar a ser destruido y queremos liberar memoria que este ha usado.
// example on constructors and destructors #include <iostream> using namespace std; class CRectangle { int *width, *height; public: CRectangle (int,int); ~CRectangle (); int area (void) {return (*width * *height);} }; CRectangle::CRectangle (int a, int b) { width = new int; height = new int; *width = a; *height = b; } CRectangle::~CRectangle () { delete width; delete height; } int main () { CRectangle rect (3,4), rectb (5,6); cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; return 0; } rect area: 12 rectb area: 30

Constructores Sobrecargados
Como cualquier otra funcion, un constructoe puede ser sobrecargado con variar funciones que llevan el mismo nombre pero diferentes tipos o numero de parametros. recuerde que el compilador ejecutara aquel que concuerde al momento en que una funcion con ese nombre sea llamada (Seccion 2.3, Funciones-II). En este caso, al mpento de ser declarado un objeto de la clase.

En realidad, en el casos donde declaramos una clase y no especificamos ningun constructor, el compilador automaticamente asume dos operadores sobrecargados ("default constructor" y "copy constructor"). Por ejemplo, para la clase:
class CExample { public: int a,b,c; void multiply (int n, int m) { a=n; b=m; c=a*b; }; };

sin constructores, el compilador automaticamente asume que tiene las siguientes funciones constructores miembro:

Constructor vacio Es un constructor sin parametros definido como nop (bloque vacio de instrucciones). No hace nada.
CExample::CExample () { };

Constructor por copia Es un constructor con un unico parametro de su mismo tipo que asigna a todos los miembros variables no estaticos de la clase del objeto una copia del objeto pasado.
CExample::CExample (const CExample& rv) { a=rv.a; b=rv.b; c=rv.c; }

Es importante hacer este par de constructores por defecto: el constructor vacio y el costructor por copia existen solo si no hay otros constructores explicitamente declarados. En caso que cualquier otro constructor con cualquier numero de parametros sea declarado, ninguno de estos dos constructores por defecto existiran. Pero si usted quiere que esten alli, debe definirlos por usted mismo. Por supuesto, usted puede tambien sobrecargar el contructor de la clase proveiendo diferentes constructores para cuando usted pase parametros entre parentesis y cuando no (vacio):
// overloading class constructors #include <iostream> using namespace std; class CRectangle { int width, height; public: CRectangle (); CRectangle (int,int); int area (void) {return (width*height);} }; CRectangle::CRectangle () { width = 5; rect area: 12 rectb area: 25

height = 5; } CRectangle::CRectangle (int a, int b) { width = a; height = b; } int main () { CRectangle rect (3,4); CRectangle rectb; cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl; }

En este caso rectb fue declarado sin parametros, pero fue inicializado con el constructor que no tiene parametros, el cual declara ambos width y height con el valor de 5. Note que si declaramos un nuevo objeto y no queremos pasar parametros a el no incluimos los parentesis ():
CRectangle rectb; // right CRectangle rectb(); // wrong!

Punteros a clases
Es perfectamente valido crear punteros apuntando a clases, en orden de hacer esto simplemente debemos considerar que una vez declarada, la clase se vuelve un tipo valido, entonces use el nombre de la clase como el tipo del puntero. Por ejemplo:
CRectangle * prect;

es un puntero a un objeto de la clase CRectangle. Como pasa en las estructuras, referenciar directamente a un miembro de un objeto apuntado por un objeto deberia usar el operador->. Aqui esta un ejemplo com algunas posibles combinaciones:
// pointer to classes example #include <iostream> using namespace std; class CRectangle { int width, height; public: void set_values (int, int); int area (void) {return (width * height);} }; a area: 2 *b area: 12 *c area: 2 d[0] area: 30 d[1] area: 56

void CRectangle::set_values (int a, int b) { width = a; height = b; } int main () { CRectangle a, *b, *c; CRectangle * d = new CRectangle[2]; b= new CRectangle; c= &a; a.set_values (1,2); b->set_values (3,4); d->set_values (5,6); d[1].set_values (7,8); cout << "a area: " << a.area() << endl; cout << "*b area: " << b->area() << endl; cout << "*c area: " << c->area() << endl; cout << "d[0] area: " << d[0].area() << endl; cout << "d[1] area: " << d[1].area() << endl; return 0; }

A continuacion uste tiene un resumen sobre como usted puede leer un puntero y operadores de clase (*, &, ., ->, [ ]) que aparecen en el ejemplo previo:
*x puede ser leido: &x puede ser leido: x.y puede ser leido: (*x).y puede ser leido: x->y puede ser leido: al anterior) x[0] puede ser leido: x[1] puede ser leido: x[n] puede ser leido: apuntado por x direccion de x miembro y del objeto x miembro y del objeto apuntado por x miembro y del objeto apuntado por x (equivalente primer objeto apuntado por x segundo obeto apuntado por x (n+1)esimo objeto apuntado por x

Asegurese de entender la logica de todas ellas antes de continuar avanzando. Si tiene dudas, lea de nuevo esta seccion y/o consulte la secciones "3.3, Punteross" y "3.5, Estructuras".

Clases definidas con la palabra reservada struct


El lenguaje C++ ha extendido la palabra reservada de C struct la misma funcionalidad de la palabra reservada de C++ class excepto que sus miembros son public por defecto a pesar de sean private.

De calquier forma, debido a que ambas class y struct tienen casi la misma funcionalidad en C++, struct es usualmente usado para solo estructuras de datos y class para clases que tienen procedimientos y funciones miembros.

Seccin 4.2

Sobrecarga de operadores
C++ incorpora la opcin para usar un lenguaje standard de operadores entre clases adems de entre tipos. Por ejemplo:
int a, b, c; a = b + c;

es perfectamente valido, ya que la diferentes variables de la adicin son todas tipos fundamentales. Sin embargo, no es tan obvio que podamos hacer la siguiente operacin (en realidad es incorrecta):
struct { char product [50]; float price; } a, b, c; a = b + c;

La asignacin de una clase (o struct) a otra del mismo tipo esta permitida ( constructor copia por defecto). lo que podra producir un error seria la operacin de adicin, que en principio no es valido entre tipos de datos no fundamentales.

Pero gracias a la habilidad de C++ para sobrecargar operadores, podemos lograr hacer eso. Los objetos derivados de tipos compuestos tal como el anterior puede aceptar operadores los cuales no serian aceptados de otra manera, y podemos igual modificar el efecto de los operadores que ya ellos admiten. Aqu esta una lista de todos los operadores que pueden ser sobrecargados:
+ <<= ~ >>= &= * == ^= / != |= = <= && < >= || > ++ %= += -[] -= % () *= & new /= << ^ ! delete >> |

Para sobrecargar un operador solo necesitamos escribir una funcin miembro de la clase cuyo nombre es operator seguido por el operador que queremos sobrecargar, siguiendo este prototipo:
type operator sign (parameters);

Aqu viene un ejemplo que involucra el operador +. Vamos a sumar los vectores bidimensionales a(3,1) y b(1,2). La adicin de dos vectores bidimensionales es una operacin tan simple como sumar las dos coordenadas x para obtener la coordenada x resultante y anlogo para la coordenadas y. En este caso al resultado ser (3+1,1+2) = (4,3).

// vectors: overloading operators example #include <iostream> using namespace std; class CVector { public: int x,y; CVector () {}; CVector (int,int); CVector operator + (CVector); }; CVector::CVector (int a, int b) { x = a; y = b; } CVector CVector::operator+ (CVector param) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp); } int main () { CVector a (3,1); CVector b (1,2); CVector c; c = a + b; cout << c.x << "," << c.y; return 0; }

4,3

Si esta enredado viendo CVector muchsimas veces, considere que algunas de ellas hacen referencia al nombre e la clase CVector y otras son funciones con ese nombre. No las confunda:
CVector (int, int); // function name CVector (constructor) CVector operator+ (CVector); // function operator+ that returns CVector type La funcin operator+ de la clase CVector es la que esta a cargo de sobrecargar el operador

aritmtico +. Este puede ser llamado de cualquiera de estas dos maneras:


c = a + b; c = a.operator+ (b);

Note que tambin hemos incluido el constructor vaci (sin parmetros) y lo hemos definido de instrucciones no-op:
CVector () { };

esto es necesario, por que ya existe otro constructor,


CVector (int, int);

entonces ninguno de los constructores por defecto existir en CVector si no lo declaramos explcitamente como hemos hecho. De otro modo la declaracin
CVector c;

incluido en main() no seria valida.

De cualquier manera, tenemos que advertirle que un bloque no-op no es una implantacin recomendable para un constructor, ya que no complementa la funcionalidad mnima que un constructor debera tener, la cual es la inicializacin de todas las variables en la clase. En nuestro caso dejamos a las variables x y y indefinidas. adems, una declaracin mas aconsejable habra de ser algo similar a esto:
CVector () { x=0; y=0; };

que por simplicidad no se incluye en el cdigo.

tambin como un clase incluye por defecto un constructor vaci y copia, incluye una definicin por defecto para el operador de asignacin assignation operator (=) entre dos clases del mismo tipo. Este copia el contenido entero de la data miembro no-esttica del objeto parmetro (el que esta a la derecha del signo) al del lado izquierdo. Por supuesto, usted puede redefinirlo para cualquier otra funcionalidad que quiera de este operador, como por ejemplo, copiar solo ciertos miembros de la clase. La sobrecarga de operadores no forza su operacin a mantener una relacin matemtica o el usual significado del operador, aunque es recomendable. Por ejemplo, no es muy lgico usar el operador + para restar dos clases o el operador == para complementar con ceros una clase, aunque es perfectamente posible de hacer. Aunque el prototipo de una funcin operator+ pueda verse obvia ya que toma el lado derecho del operador como parmetro de la funcin operator+ del objeto del lado izquierdo, otros operadores no son tan claros. Aqu tiene una tabla con un resumen sobre como los diferentes funciones operator deben ser declaradas (reemplazando @ por el operador en cada caso):
Expresin
@a a@

Operador (@)

funcin miembro

funcin global
operator@(A) operator@(A, int)

+ - * & ! ~ ++ A::operator@() -++ -A::operator@(int)

a@b

+ - * / % ^ & | < > == != <= A::operator@(B) >= << >> && || , = += -= *= /= %= ^= &= |= <<= >>= [ ] () ->

operator@(A, B)

a@b

A::operator@(B)

a(b, c...) a->b

A::operator()(B, C...) A::operator->()

* donde a es un objeto de la clase A, b es un objeto de la clase B y c es un objeto de la clase C. Puede ver en este panel que hay dos formas de sobrecargar algunos operadores: como funcin miembro y como funcin global. Este uso es indistinto aunque le recuerdo que las funciones que no son miembros de una clase no pueden acceder a los miembros private o protected de la clase excepto si la funcin global es amiga friend de la clase (friend es explicado mas adelante).

La palabra reservada this


La palabra reservada this representa dentro de una clase la direccin de memoria del objeto de esa clase que esta siendo ejecutado. Es un puntero cuyo valor entero es siempre la direccin de el objeto.

Este puede ser usado para verificar si el parmetro pasado a una funcin miembro de un objeto es el objeto en si. Por ejemplo,
// this #include <iostream> using namespace std; class CDummy { public: int isitme (CDummy& param); }; int CDummy::isitme (CDummy& param) { if (&param == this) return 1; else return 0; } int main () { CDummy a; CDummy* b = &a; if ( b->isitme(a) ) yes, &a is b

cout << "yes, &a is b"; return 0; }

Es tambin usado frecuentemente en la funcin miembro operator= que retorna objetos por referencia (evitando usar objetos temporales). siguiendo con el ejemplo del vector visto anteriormente podramos haber escrito una funcin operator= como esta:
CVector& CVector::operator= (const CVector& param) { x=param.x; y=param.y; return *this; }

En realidad es un probable cdigo generado por defecto para una clase si no incluimos funcin miembro operator=.

Miembros estticos
Una clase puede contener miembros estticos, tanto data como funciones.

Los miembros dato estticos de una clase son tambin conocidos como "class variables" o variables de clase, porque su contenido no depende de ningn objeto. Hay solo un valor para todos los objetos de la misma clase. Por ejemplo, puede ser usado para una variable dentro de una clase que contenga el numero de objetos de una clase que ha sido declarada, como en el siguiente ejemplo:
// static members in classes #include <iostream> using namespace std; class CDummy { public: static int n; CDummy () { n++; }; ~CDummy () { n--; }; }; int CDummy::n=0; int main () { CDummy a; CDummy b[5]; CDummy * c = new CDummy; cout << a.n << endl; delete c; cout << CDummy::n << endl; return 0; } 7 6

En realidad, los miembros estticos tienen las mismas propiedades que las variables globales pero estas disfrutan de un entorno o mbito de clase. Por esta razn, y para evitar que esta sea declarada varias veces, acorde al ANSI-C++ standard, podemos solo incluir el prototipo (declaracin) en la declaracin de la clase pero no la definicin (inicializacin). En orden de inicializar un miembro dato esttico debemos incluir una definicin formal fuera de la clase, en el contexto global, como en el ejemplo previo. porque es una variable nica para todos los objetos de la misma clase, puede ser referido como un miembro de cualquier objeto de esa clase como tambin directamente por el nombre de la clase (por supuesto esto es solo valido para miembros estticos):
cout << a.n; cout << CDummy::n;

Estas dos llamadas incluidas en el ejemplo previo se estn refiriendo a la misma variable n dentro de la clase CDummy.

Una vez mas, le recordamos que en realidad es una variable global. La nica diferencia es su nombre fuera de la clase. As como podemos incluir datos estticos dentro de una clase, podemos tambin incluir funciones estticas. Ellas representan lo mismo: son funciones globales que son llamadas como si fueran miembros del objeto de una clase dada. Solo pueden referir a datos estticos, en ningn caso a miembros no estticos de la clase, as como no permiten el uso de la palabra reservada this, ya que esta hace referencia a un puntero a objeto y estas funciones en realidad no son miembro de ningn objeto a menos que sean miembros directos de la clase.

Seccin 4.3

Relaciones entre clases Funciones amigas (palabra reservada friend )


En la seccion anterior hemos visto que habian tres niveles de proteccion interna para diferentes miembros de una clase: public, protected y private. En el caso de los miembros protected y private, estos no podrian ser accedidos desde afuera de la misma clase a la cual fueron declarados. No obstante, esta regla puede ser transgredida, con el uso de la palabra reservada friend en una clase, podemos permitir a una funcion externa ganar acceso a los miembros protected y private de una clase. En orden de permitir a una funcion externa tener acceso a los miembros private y protected de una clase tenemos que dseclarar el prototipo de la funcion externa que ganara el acceso precedido por la palabra reservada friend dentro de la declaracion de la

clase que comparte sus miembros. en el siguiente ejemplo declaramos la funcion amiga duplicate:
// friend functions #include <iostream> using namespace std; class CRectangle { int width, height; public: void set_values (int, int); int area (void) {return (width * height);} friend CRectangle duplicate (CRectangle); }; void CRectangle::set_values (int a, int b) { width = a; height = b; } CRectangle duplicate (CRectangle rectparam) { CRectangle rectres; rectres.width = rectparam.width*2; rectres.height = rectparam.height*2; return (rectres); } int main () { CRectangle rect, rectb; rect.set_values (2,3); rectb = duplicate (rect); cout << rectb.area(); } 24

Dentro de la funcion duplicate, que es una amiga de CRectangle, hemos sido habilitados para acceder a los miembros width y height de diferentes objetos de tipo CRectangle. Note que ni en la declaracion de duplicate() ni en su uso posterior en main() hemos considerado duplicate como miembro de la clase CRectangle. No lo es. La funcion amiga puede servir, por ejemplo, para conducir operaciones entre dos clases diferentes. Generalmente el uso de funciones amigas esta fuera de una metodologia de programacin orientada a objetos, y siempre que sea posible es mejor el uso de miembros de la misma clase para hacer el proceso. Tal como en el ejemplo anterior, hubiera sido mas corto integrar duplicate() dentro de la clase CRectangle.

Clases amigas (friend)


Asi como tenemos la posibilidad de definir una funcion amiga, podemos tambien definir una clase como amiga de otra, permitiendo a la segunda acceso a los miembros protected y private de la primera.
// friend class #include <iostream> using namespace std; class CSquare; class CRectangle { int width, height; public: int area (void) {return (width * height);} void convert (CSquare a); }; class CSquare { private: int side; public: void set_side (int a) {side=a;} friend class CRectangle; }; void CRectangle::convert (CSquare a) { width = a.side; height = a.side; } int main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); cout << rect.area(); return 0; } 16

En este ejemplo hemos declarado CRectangle como amiga de CSquare y que CRectangle puede accesar a los miembros protected y private de CSquare, mas concretamente CSquare::side, que define la magnitud (ancho) del lado del cuadrado. Puede ver tambien algo nuevo en la primera instruccion del programa, que es el prototipo vacio de la clase CSquare. Esto es necesario porque dentro de la declaracion de CRectangle referimos a CSquare (como parametro en convert()). La definicion de CSquare es incluida luego, y si no incluimos una definicion previa para CSquare esta clase no seria visible dentro de la definicion de CRectangle.

Considere que la amistad no es correspondida si no se especifica explicitamente. En nuestro ejemplo de CSquare, CRectangle es considerada una clase amiga, pero CRectangle no hace lo propio con CSquare, y CRectangle puede accesar a los miembros protected y private de CSquare pero no en el sentido inverso. Aunque nada evita que declaremos a CSquare como amiga de CRectangle.

Herencia entre clases


Una importante caracteristica de las clases es la herencia. Esta permite crear un objeto derivado de otro, y asi este puede incluir algunos miembros mas sus propios. Por ejemplo, vamos a suponer que queremos declarar una serie de clases que describen poligonos como nuestro CRectangle, o CTriangle. Ellos tienen ciertas caracteristicas en comun, tal como que ambos pueden ser descritos principalmente solo por dos lados: altura y base. Esto puede ser representado en el mundo de clases con una clase CPolygon desde la cual derivan las dos referidas, CRectangle and CTriangle.

La clase CPolygon contendria miembros que son comunes para todos los poligonos. En nuestro caso: width y height. Y CRectangle y CTriangle serian sus clases derivadas. Las clases derivadas de otras heredan todos los miembros visibles de la clase base. Esto significa que si la clase base incluye un miembro A y lo derivamos a otra clase con otro miembro llamado B, la clase derivada contendra ambas A y B. En orden de derivar una clase desde otra, debemos usar el operador : (dos puntos) en la declaracion de la clase derivada de la siguiente manera:
class derived_class_name: public base_class_name;

donde derived_class_name es el nombre de la clase derivada y base_class_name es el nombre en la cual esta basada. public puede ser reemplazada por cualquiera de los otros especificadores de acceso protected o private, y describe el acceso para los miembros heredados, como veremos ahora en este ejemplo:
// derived classes #include <iostream> using namespace std; class CPolygon { protected: 20 10

int width, height; public: void set_values (int a, int b) { width=a; height=b;} }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); cout << rect.area() << endl; cout << trgl.area() << endl; return 0; }

Como puede ver, los objetos de las clases CRectangle y CTriangle cada una contiene miembros de CPolygon, que son: width, height y set_values(). El especificador protected es similar a private, su unica diferencia aparece cuando se derivan clases. Cuando derivamos una clase, los miembros protected de la clase base pueden ser usados por otros miembros de la clase derivada, sin embargo a los miembros private no puede. Ya que queriamos que width y height tuvieran la abilidad de ser manipulados por miembros de las clases derivadas CRectangle y CTriangle y no solo por miembros de CPolygon, hemos usado acceso protected en vez de private. Podemos resumir los diferentes tipos de acceso de acuerdo a quienes pueden accederlos de la siguiente manera: Acceso
public protected private

miembros de la misma clase si miembros de clases derivadas si

si si

si no

no miembros si no no donde "no miembros" representa cualquier referencia desde afuera de la clase, tal como desde main(), desde otra clase o desde cualquier funcion, tanto global como local.

En nuestro ejemplo, los miembros heredados por CRectangle y CTriangle siguen con el mismo permiso de acceso como en la clase base CPolygon:
CPolygon::width CRectangle::width CPolygon::set_values() CRectangle::set_values() // protected access // protected access // public access // public access

Esto es porque hemos derivado a una clase desde otra como public, recuerde:
class CRectangle: public CPolygon; Esta palabra reservada public representa el minimo nivel de proteccion que el miembro heredado de la clase base (CPolygon) debe adquirir en la nueva clase (CRectangle). EL

minimo nivel de acceso para los miembros heredados pueden ser cambiados especificando protected o private en vez de public. por ejemplo, daughter es una clase derivada de mother que definimos de esta manera:
class daughter: protected mother; esto establecera protected como el minimo nivel de acceso para los miembros de daughter que ella herede desde mother. Esto es, todos los miembros que eran public en mother seran protected en daughter, que seria el minimo nivel al cual ellas pueden ser heredadas. Por supuesto, esto no restringiria que daughter pudiera sus propios miembros public. El minimo nivel seria establecido unicamente para los miembros heredados de mother.

El uso mas comun de un nivel de herencia diferente de public es private que sirve para encapsular completamente la clase base, ya que, es ese caso, nadie excepto su propia clase estara habilitada para acceder a los miembros de la clase base desde la cual es derivada. De cualquier manera, en la mayoria de los casos las clases son derivadas como public. Si ningun nivel de acceso es explicitamente escrito, private es asumido para las clases creadas con la palabra class y public para aquelas creadas con struct.

Que es heredado desde la clase base?


En principio cada uno de los miembros de una clase base excepto:

Constructor y destructor
miembro operator=()

friends

Aunque el constructor y destructor de la clase base no es heredado, el constructor por omision (i.e. constructor sin parametros) y el destructor de la clase base siempre son llamados cuando un nuevo objeto de la clase derivada es creado o destruido. Si la clase base no tiene constructor por omision o usted quiere que un constructor sobrecargado sea llamado cuando un nuevo objeto derivado sea creado, usted puede especificarlos en cada definicion de constructor de la clase derivada:

derived_class_name (parameters) : base_class_name (parameters) {}

Por ejemplo:
// constructors and derivated classes #include <iostream> using namespace std; class mother { public: mother () { cout << "mother: no parameters\n"; } mother (int a) { cout << "mother: int parameter\n"; } }; class daughter : public mother { public: daughter (int a) { cout << "daughter: int parameter\n\n"; } }; class son : public mother { public: son (int a) : mother (a) { cout << "son: int parameter\n\n"; } }; int main () { daughter cynthia (1); son daniel(1); return 0; } mother: no parameters daughter: int parameter mother: int parameter son: int parameter

Observe la diferencia entre cual constructor de mother es llamado cuando un nuevo objeto daughter es creado y cual cuando es un objeto son son. La diferencia es a causa de la declaracion del constructor de daughter y son:
daughter (int a) son (int a) : mother (a) // nothing specified: call default constructor // constructor specified: call this one

Herencia multiple
En C++ es perfectamente posible que una clase herede campos y metodos desde mas de una clase simplemente separando las diferentes clases base con comas en la declaracion de la clase derivada. por ejemplo, si tenemos especificada una clase para imprimir en pantalla (COutput) y queriamos que nuestras clases CRectangle y CTriangle tambien heredaran sus miembros en adicion a los de CPolygon podriamos escribir:

class CRectangle: public CPolygon, public COutput { class CTriangle: public CPolygon, public COutput {

aqui esta el ejemplo completo:


// multiple inheritance #include <iostream> using namespace std; class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b;} }; class COutput { public: void output (int i); }; void COutput::output (int i) { cout << i << endl; } class CRectangle: public CPolygon, public COutput { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon, public COutput { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); rect.output (rect.area()); trgl.output (trgl.area()); return 0; } 20 10

Seccin 4.4

Polimorfismo

Para un entendimiento apropiado de esta seccin debera saber claramente como utilizar apuntadores y herencia entre clases. Recomiendo que si algunas de estas expresiones le parecen extraas, revise las secciones indicadas:
int a::b(c) {}; // Clases (Seccin 4.1) a->b // Apuntadores y objetos (Section 4.2) class a: public b; // Relaciones entre clases (Section 4.3)

Apuntadores a clase base


Una de las ventajas ms grandes de derivar clases es que un apuntador a una clase derivada es compatible de tipo con un apuntador a su clase base. Esta seccin est completamente dedicada a aprovechar esta poderosa caracterstica de C++. Por ejemplo, vamos a reescribir nuestro programa sobre el rectngulo y el tringulo de la seccin previa considerando esta propiedad:
// pointers to base class #include <iostream.h> class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; CPolygon * ppoly1 = CPolygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << rect.area() << endl; cout << trgl.area() << endl; return 0; } 20 10

La funcin main crea dos apuntadores que apuntan a objetos de la clase CPolygon, que son *ppoly1 y *ppoly2. stos son asignados a la direccin de rect y trgl, y ya que son objetos de clases derivadas de CPolygon son asignaciones vlidas. La nica limitacin de usar *ppoly1 y *ppoly2 en vez de rect y trgl es que *ppoly1 y *ppoly2 son de tipo CPolygon* y por lo tanto podemos referenciar slo a los miembros que CRectangle y CTriangle heredan de CPolygon. Por esta razn, cuando se invoca a area() no pudimos utilizar los apuntadores *ppoly1 y *ppoly2. Para hacer posible que los apuntadores a la clase CPolygon admitan area() como un miembro vlido, sta debera tambin ser declarada en la clase base y no slo en las derivadas. (vea la seccin siguiente).

Miembros virtuales
Para declarar un elemento de una clase que vamos a redefinir en clases derivadas debemos precederla con la palabra clave virtual para que el uso de apuntadores a objetos de esa clase sea posible.

Observe el siguiente ejemplo:


// virtual members #include <iostream.h> class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } virtual int area (void) { return (0); } }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; 20 10 0

CPolygon poly; CPolygon * ppoly1 = CPolygon * ppoly2 = &trgl; CPolygon * ppoly3 = &poly; ppoly1->set_values (4,5); ppoly2->set_values (4,5); ppoly3->set_values (4,5); cout << ppoly1->area() << endl; cout << ppoly2->area() << endl; cout << ppoly3->area() << endl; return 0; }

Ahora las tres clases (CPolygon, CRectangle y CTriangle) tienen los mismos miembros: width, height, set_values() y area().
area()

ha sido definida como virtual ya que es luego redefinida en las clases derivadas. Puede verificar si quiere, que si borra esta palabra (virtual) del cdigo y luego ejecuta el programa, el resultado ser 0 para los tres polgonos en vez de 20,10,0. Esto ocurre porque en vez de llamar la funcin area() correspondiente para cada objeto (CRectangle::area(), CTriangle::area() y CPolygon::area(), respectively), se llamar a CPolygon::area() para todos ellos ya que las llamadas son via apuntador a CPolygon. Por lo tanto, lo que la palabra virtual hace es permitir que un miembro de una clase derivada con el mismo nombre que el que est en la clase base se pueda invocar cuando un apuntador a ella cuando se utiliza un apuntador a ella, como en el ejemplo anterior. Note que a pesar de su virtualidad tambin hemos podido declarar un objeto de tipo CPolygon e invocar a su funcin area(), que siempre retorna 0 como resultado.

Clases base abstractas


Las clases abstractas bsicas son algo muy similar a la clase CPolygon de nuestro ejemplo previo. La nica diferencia es que en nuestro ejemplo previo hemos definido una funcin area() vlida para objetos que fueran de clase CPolygon (como el objeto poly), en cambio en una clase base abstracta podramos dejar simplemente sin escribir esta funcin anexando =0 (igual a cero) a la funcin de la declaraci.

La clase CPolygon podra ser as:


// abstract class CPolygon class CPolygon { protected: int width, height; public: void set_values (int a, int b)

{ width=a; height=b; } virtual int area (void) =0; };

Observe como aadimos =0 a virtual int area (void) en vez de especificar una implementacin para la funcin. Este tipo de funcin es llamado una funcin virtual pura, y todas las clases que contienen una funcin virtual pura son consideradas clases base abstractas.

La mayor diferencia de una clase base abstracta es que no se pueden crear instancias (objetos) de ella, pero podemos crear apuntadores a ellas. Por lo tanto, una delcaracin como:
CPolygon poly;

sera incorrecta para la clase base abstracta declarada arriba. Sin embargo los apuntadores:
CPolygon * ppoly1; CPolygon * ppoly2

son perfectamente vlidos. Esto es porque la funcin virtual pura que incluye no est definida y es imposible crear un objeto si no tiene todos sus miembros definidos. A pesar de esto un apuntador que apunta a un objeto de una clase derivada donde esta funcin ha sido definida es perfectamente vlido.

Aqu tiene el ejemplo completo:


// virtual members #include <iostream.h> class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } virtual int area (void) =0; }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } }; int main () { 20 10

CRectangle rect; CTriangle trgl; CPolygon * ppoly1 = CPolygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << ppoly1->area() << endl; cout << ppoly2->area() << endl; return 0; }

Si usted revisa el programa observar que podemos referenciar objetos de diferentes clases utilizando un nico tipo de apuntador (CPolygon*). Esto puede ser tremendamente util. Imagine, ahora podemos crear una funcin miembro de CPolygon que pueda imprimir por pantalla el resultado de la funcin area() independientemente de que son las clases derivadas.
// virtual members #include <iostream.h> class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } virtual int area (void) =0; void printarea (void) { cout << this->area() << endl; } }; class CRectangle: public CPolygon { public: int area (void) { return (width * height); } }; class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; CPolygon * ppoly1 = CPolygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); ppoly1->printarea(); ppoly2->printarea(); return 0; 20 10

Recuerde que this representa un apuntador al objeto cuyo cdigo est siendo ejecutado. Las clases abstractas y los miembros virtuales garantizan a C++ las caractersticas polimrficas que hacen a la Programacin Orientada por Objetos un instrumento tan til. Por supuesto, hemos visto la manera ms fcil de utilizar estas caractersticas, pero imagnelas aplicadas a arreglos de objetos o objetos asignados a travs de memoria dinmica.

Seccin 5.1

Plantillas
Las plantillas son una nueva caracterstica introducida por el estndar ANSI-C++. Si utiliza un compilador C++ que no est adaptado a este estndar es posible que no las pueda utilizar.

Plantillas de Funciones
Las plantillas permiten crear funciones genricas que admiten cualquier tipo de dato como parmetros y retornan un valor sin tener que sobrecargar la funcin con todos los posibles tipos de datos. Hasta cierto punto cumplen la funcionalidad de un macro. Su prototipo es cualquiera de los dos siguientes:
template <class identifier> function_declaration; template <typename identifier> function_declaration;

la nica diferencia entre ambos prototipos es el uso de la palabra reservada class o typename, su uso es indistinto ya que ambas expresiones tienen exactamente el mimso significado y actuan exactamente igual.

Por ejemplo, para crear una plantilla de funcin que retorna el mayor de dos objetos podramos usar:
template <class GenericType> GenericType GetMax (GenericType a, GenericType b) { return (a>b?a:b); }

Como especifica la primera lnea, hemos creado una plantilla para un tipo de dato genrico que hemos llamado GenericType. Por lo tanto, en la funcin que sigue, GenericType en un tipo de dato vlido y es usado como el tipo para sus dos parmetros a y b y como el tipo de retorno para la funcin GetMax.

GenericType

todavia no representa algn tipo de dato concreto; cuando la funcin GetMax sea llamada podremos invocarla con cualquier tipo de dato vlido. Este tipo de dato servir como patrn y reemplazar a GenericType en la funcin. La manera de invocar a una plantilla de funcin con un tipo patrn es la siguiente:
function <patron> (parametros);

As, por ejemplo, para invocar a GetMax y comparar dos valores enteros de tipo int podemos escribir:
int x,y; GetMax <int> (x,y);

entonces GetMax ser invocada como si cada ocurrencia de GenericType fuera reemplazada por int.

Aqu est el ejemplo completo:


// function template #include <iostream.h> template <class T> T GetMax (T a, T b) { T result; result = (a>b)? a : b; return (result); } int main () { int i=5, j=6, k; long l=10, m=5, n; k=GetMax<int>(i,j); n=GetMax<long>(l,m); cout << k << endl; cout << n << endl; return 0; } 6 10

(En este caso hemos llamado al tipo genrico T en vez de GenericType ya que es ms corto y es adems uno de los identificadores ms usuales usado para plantillas, aunque es vlido utilizar cualquier identificador vlido). En el ejemplo utilizamos la misma funcin GetMax() con argumentos de tipo int y long habiendo escrito una nica implementacin de la funcin. Es decir, hemos escrito una plantilla de funcin y la llamamos con dos patrones diferentes. Como puede ver, dentro de nuestra plantilla de funcin GetMax() el tipo T puede ser utilizado para declarar nuevos objetos:

T result; result es un objeto de tipo T, como a y b, o sea, del tipo que encerremos entre <> cuando

invoquemos a nuestra plantilla de funcin.

En este caso concreto donde el tipo genrico T es utilizado como parmetro para la funcin GetMax el compilador puede encontrar automticamente que tipo de dato se le pasa sin tener que especificarlo con los patrones <int> o <long>. Pudimos haber escrito:
int i,j; GetMax (i,j);

ya que i y j son de tipo int el compilador asumira automticamente que la funcin deseada es para el tipo int. Este mtodo implcito es ms usual y producira el mismo resultado:
// function template II #include <iostream.h> template <class T> T GetMax (T a, T b) { return (a>b?a:b); } int main () { int i=5, j=6, k; long l=10, m=5, n; k=GetMax(i,j); n=GetMax(l,m); cout << k << endl; cout << n << endl; return 0; } 6 10

Observe como en este caso, dentro de la funcin main() llamamos a nuestra plantilla de funcin GetMax() sin especificar explcitamente el tipo entre <>. El compilador automaticamente determina que tipo se necesita en cada llamada. Ya que nuestra funcin plantilla incluye solamente un tipo de dato (class T) y los dos argumentos que admite son ambos de ese mismo tipo, no podemos llamar a nuestra funcin plantilla con dos objetos de diferentes tipos como parmetros:
int i; long l; k = GetMax (i,l);

Esto sera incorrecto, ya que nuestra funcin espera dos argumentos de el mismo tipo (o clase).

Tambin podemos hacer funciones-plantilla que admitan ms de una clase genrica o tipo de dato. Por ejemplo:

template <class T, class U> T GetMin (T a, U b) { return (a<b?a:b); }

En este caso, nuestra funcin plantilla GetMin() admite dos parmetros de diferentes tipos y retorna un objeto del mismo tipo que el primer parmetro (T) que se pasa. Por ejemplo, despus de esa declaracin podramos llamar a la funcin escribiendo:
int i,j; long l; i = GetMin<int,long> (j,l);

o simplemente
i = GetMin (j,l); inclusive, aunque j y l sean de tipos diferentes.

Plantillas de clases
Tambin tenemos la posibilidad de escribir plantillas de clases, para que una clase pueda tener miembros basados en tipos genricos que no necesitan ser definidos al momento de crear la clase o cuyos miembros usan estos tipos genricos. Por ejemplo:
template <class T> class pair { T values [2]; public: pair (T first, T second) { values[0]=first; values[1]=second; } };

La clase que acabamos de definir sirve para almacenar dos elementos de cualquier tipo vlido. Por ejemplo, si quisieramos declarar un objeto de esta clase para almacenar dos valores enteros de tipo int con los valores 115 y 36 escribiramos:
pair<int> myobject (115, 36);

esta misma clase servira para crear un objeto para almacenar cualquier otro tipo:
pair<float> myfloats (3.0, 2.18);

La nica funcin miembro ha sido definida inline dentro de la declaracin de la clase. Si definimos una funcin miembro fuera de la declaracin siempre debemos preceder la definicin con el prefijo template <... >.
// class templates #include <iostream.h> template <class T> 100

class pair { T value1, value2; public: pair (T first, T second) {value1=first; value2=second;} T getmax (); }; template <class T> T pair<T>::getmax () { T retval; retval = value1>value2? value1 : value2; return retval; } int main () { pair <int> myobject (100, 75); cout << myobject.getmax(); return 0; }

observe como comienza la definicin de la funcin miembro getmax:


template <class T> T pair<T>::getmax ()

Todas las Ts que aparecen son necesarias porque cada vez que declara funciones miembro debe seguir un formato similar a ste (la segunda T hace referencia al tipo retornado por la funcin, as que esto puede variar).

Especializacin de Plantilla
Una especializacin de plantilla permite a una plantilla hacer implementaciones especficas cuando el patrn es de un tipo determinado. Por ejemplo, suponga que nuestra plantilla de clase pair inclua una funcin para retornar el resultado de la operacin mdulo entre los objetos contenidos en ella, pero slamente queremos que funcione cuando el tipo contenido es int. Para el resto de los tipos queremos que esta funcin retorne 0. Esto se puede hacer de la siguiente manera:
// Template specialization #include <iostream.h> template <class T> class pair { T value1, value2; public: pair (T first, T second) 25 0

{value1=first; value2=second;} T module () {return 0;} }; template <> class pair <int> { int value1, value2; public: pair (int first, int second) {value1=first; value2=second;} int module (); }; template <> int pair<int>::module() { return value1%value2; } int main () { pair <int> myints (100,75); pair <float> myfloats (100.0,75.0); cout << myints.module() << '\n'; cout << myfloats.module() << '\n'; return 0; }

Como puede ver en el cdigo la especializacin es definida as:


template <> class class_name <type>

La especializacin es parte de una plantilla, por lo que debemos comenzar la declaracin con template <>. And indeed because it is a specialization for a concrete type, the generic type cannot be used in it and the first angle-brackets <> must appear empty. After the class name we must include the type that is being specialized enclosed between angle-brackets <>.

When we specialize a type of a template we must also define all the members equating them to the specialization (if one pays attention, in the example above we have had to include its own constructor, although it is identical to the one in the generic template). The reason is that no member is "inherited" from the generic template to the specialized one.

Valores de parmetros para plantillas


Ademas de los argumentos tipo plantilla precedidos por la palabra clave class o typename que representan un tipo, las plantillas de funciones y plantillas de clases pueden incluir otros parmetros que no son tipos siempre que sean tambin valores constantes, como por ejemplo

valores de tipos fundamentales. Como un ejemplo, vea esta plantilla de clase que sirve para almacenar arreglos:
// array template #include <iostream.h> template <class T, int N> class array { T memblock [N]; public: void setmember (int x, T value); T getmember (int x); }; template <class T, int N> array<T,N>::setmember (int x, T value) { memblock[x]=value; } template <class T, int N> T array<T,N>::getmember (int x) { return memblock[x]; } int main () { array <int,5> myints; array <float,5> myfloats; myints.setmember (0,100); myfloats.setmember (3,3.1416); cout << myints.getmember(0) << '\n'; cout << myfloats.getmember(3) << '\n'; return 0; } 100 3.1416

Es tambin posible asignar valores por defecto para cualquier parmetro de plantillas de funciones tal como se hace con parmetros de funciones. Algunos posibles ejemplos de plantillas vistos arriba:
template template template template template <class T> <class T, class U> <class T, int N> <class T = char> <int Tfunc (int)> // // // // // The most usual: one class parameter. Two class parameters. A class and an integer. With a default value. A function as parameter.