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

Programacin en C++

Introduccin
Programacin en C++/Introduccin


Contenido
[ocultar]
1 Conceptos Bsicos
o 1.1 Qu es un Lenguaje de Programacin [eliminar y referir al artculo en wikipedia]
2 Historia de C++
o 2.1 Qu es C++
3 Herramientas Necesarias
4 Consejos iniciales antes de programar
5 Ejemplos
Conceptos Bsicos[editar]
Qu es un Lenguaje de Programacin [eliminar y referir al artculo en
wikipedia][editar]
Antes de hablar de C++, es necesario explicar que un lenguaje de programacin es una
herramienta que nos permite comunicarnos e instruir a la computadora para que realice una
tarea especfica. Cada lenguaje de programacin posee una sintaxis y un lxico particular, es
decir, forma de escribirse que es diferente en cada uno por la forma que fue creado y por la
forma que trabaja su compilador para revisar, acomodar y reservar el mismo programa en
memoria.
Existen muchos lenguajes de programacin de entre los que se destacan los siguientes:
1. C
2. C++
3. Basic
4. Ada
5. Java
6. Pascal
7. Python [desarrollo]
8. Fortran
9. Smalltalk
Capitulo 1: Lo ms bsico
Historia de C++[editar]
C++ es un lenguaje de programacin creado por Bjarne Stroustrup en los laboratorios de At&T
en 1983. Stroustrup tom como base el lenguaje de programacin ms[referencia] popular en
aquella poca el cual era C.
El C++ es un derivado del mtico lenguaje C, el cual fue creado en la dcada de los 70 por la
mano del finado Dennis Ritchie para la programacin del sistema operativo [1] (un sistema
parecido a Unix es GNU/Linux), el cual surgi como un lenguaje orientado a la programacin
de sistemas (System Programming) y de herramientas (Utilities) recomendado sobre todo para
programadores expertos, y que no llevaba implementadas muchas funciones [cmo cules?]
que hacen a un lenguaje ms comprensible.
Sin embargo, aunque esto en un inicio se puede convertir en un problema, en la prctica es su
mayor virtud, ya que permite al programador un mayor control sobre lo que est haciendo.
Aos ms tarde, un programador llamado Bjarne Stroustrup, creo lo que se conoce como C++.
Necesitaba ciertas facilidades de programacin, incluidas en otros lenguajes pero que C no
soportaba, al menos directamente, como son las llamadas clases y objetos, principios usados
en la programacin actual. Para ello redise C, ampliando sus posibilidades pero
manteniendo su mayor cualidad, la de permitir al programador en todo momento tener
controlado lo que est haciendo, consiguiendo as una mayor rapidez que no se conseguira
en otros lenguajes.
C++ pretende llevar a C a un nuevo paradigma de clases y objetos con los que se realiza una
comprensin ms humana basndose en la construccin de objetos, con caractersticas
propias solo de ellos, agrupados en clases. Es decir, si yo quisiera hacer un programa sobre
animales, creara una clase llamada animales, en la cual cada animal, por ejemplo un pato,
sera un objeto, de tal manera que se ve el intento de esta forma de programar por ser un fiel
reflejo de cmo los humanos (en teora) manejamos la realidad[referencia].
Se dice que nuestro cerebro trabaja de forma relacional[referencia] (relacionando hechos), es
por ello que cada vez que recuerdas algo, (cuentas un hecho), termina siendo diferente (se
agregan u omiten partes).
Qu es C++[editar]
C++ es un lenguaje de programacin orientado a objetos que toma la base del lenguaje C y le
agrega la capacidad de abstraer tipos como en Smalltalk.
La intencin de su creacin fue el extender al exitoso lenguaje de programacin C con
mecanismos que permitieran la manipulacin de objetos. En ese sentido, desde el punto de
vista de los lenguajes orientados a objetos, el C++ es un lenguaje hbrido [por? fusionar con
el siguiente].
Posteriormente se aadieron facilidades de programacin genrica, que se sum a los otros
dos paradigmas que ya estaban admitidos (programacin estructurada y la programacin
orientada a objetos). Por esto se suele decir que el C++ es un lenguaje de programacin
multiparadigma.
Herramientas Necesarias[editar]
Las principales herramientas necesarias para escribir un programa en C++ son las siguientes:
1. Un equipo ejecutando un sistema operativo.
2. Un compilador de C++
1. Windows MingW (GCC para Windows) o MSVC (compilador de microsoft con
versin gratuita)
2. Linux (u otros UNIX): g++
3. Mac (con el compilador Xcode)
3. Un editor cualquiera de texto, o mejor un entorno de desarrollo (IDE)
1. Windows:
1. Microsoft Visual C++ (conocido por sus siglas MSVC). Incluye
compilador y posee una versin gratuita (versin express)
2. Bloc de notas (no recomendado)
3. Editor Notepad++
4. DevCpp (incluye MingW - en desuso, no recomendado, incluye tambin
un compilador)
5. Code::Blocks
2. Linux (o re-compilacin en UNIX):
1. Gedit
2. Kate
3. KDevelop
4. Code::Blocks
5. SciTE
6. GVim
3. Mac:
1. Xcode (con el compilador trae una IDE para poder programar)
4. Tiempo para practicar
5. Paciencia
Adicional
1. Ingls (Recomendado)
2. Estar familiarizado con C u otro lenguaje derivado (PHP, Python, etc).
Es recomendable tener conocimientos de C, debido a que C++ es una mejora de C, tener los
conocimientos sobre este te permitira avanzar mas rapido y comprender aun mas. Tambien,
hay que recordar que C++, admite C, por lo que se puede programar (reutilizar), funciones de
C que se puedan usar en C++.
Aunque No es obligacion aprender C, es recomendable tener nociones sobre la programacin
orientada a objetos en el caso de no tener conocimientos previos de programacin
estructurada. Asimismo, muchos programadores recomiendan no saber C para saber C++, por
ser el primero de ellos un lenguaje imperativo o procedimental y el segundo un lenguaje de
programacin orientado a objetos.
Consejos iniciales antes de programar[editar]
Con la prctica, se puede observar que se puede confundir a otros programadores con el
cdigo que se haga. Antes de siquiera hacer una lnea de cdigo, si se trabaja con otros
programadores, ha de tenerse en cuenta que todos deben escribir de una forma similar el
cdigo, para que de forma global puedan corregir el cdigo en el caso de que hubieran errores
o rastrearlos en el caso de haberlos.
Tambin es muy recomendable hacer uso de comentarios (comenta todo lo que puedas, hay
veces que lo que parece obvio para ti, no lo es para los dems) y tratar de hacer un cdigo
limpio y comprensible, especificando detalles y haciendo tabulaciones, aunque te tome un
poco mas de tiempo, es posible que mas adelante lo agradezcas tu mismo.

Ejemplos[editar]
/*PROGRAMA QUE NOS PERMITE SABER SI EL NUMERO INGRESADO ES PAR O NO*/
1. include <stdio.h>
2. include <stdlib.h>
int main () {
int numero;
printf ("Ingrese el valor de numero: ");
scanf ("%d", &numero);
if(numero%2==0)
printf ("\n***El numero es par\n");
else
printf ("\n***El numero es impar\n");
putchar ('\n');
system("pause");
return EXIT_SUCCESS;
}

Programacin en C++
Lo ms bsico
Programacin en C++/Lo ms bsico
Introduccion Iteraciones y decisiones
Contenido
[ocultar]
1 Proceso de desarrollo de un programa
o 1.1 Comentarios
o 1.2 Utilizacin de la consola o terminal
2 Sintaxis
o 2.1 El punto y coma
o 2.2 Espacios y tabuladores
3 Tipos primitivos
o 3.1 El modificador long
o 3.2 El Modificador short
o 3.3 El Modificador unsigned
o 3.4 El Modificador register
o 3.5 El Modificador volatile
o 3.6 El Modificador static
o 3.7 Espacio que ocupan la variables (en mquinas x86)
3.7.1 Rango de los Tipos Primitivos
4 Tipos enumerados (enum)
5 Tipos definidos por el usuario
6 Variables y constantes
Proceso de desarrollo de un programa[editar]
Si se desea escribir un programa en C++ se debe ejecutar como mnimo los siguientes pasos:
1. Escribir con un editor de texto plano un programa sintcticamente vlido o usar un
entorno de desarrollo (IDE) apropiado para tal fin
2. Compilar el programa y asegurarse de que no han habido errores de compilacin
3. Ejecutar el programa y comprobar que no hay errores de ejecucin
Este ltimo paso es el ms costoso, por que en programas grandes, averiguar si hay o no un
fallo prcticamente puede ser una tarea totmica.
Como ejemplo, si se desea escribir un archivo con el nombre hola.cpp y en l escribir un
programa con emacs, por ejemplo, que es un programa de edicin de textos, se puede, en
GNU, ejecutar el siguiente comando:
$emacs hola.cpp &
Para otros sistemas operativos u otros entornos de desarrollo, no necesariamente se sigue
este paso.
A continuacin se escribe el siguiente cdigo en C++:
Ejemplo
// Aqu generalmente se suele indicar qu se quiere con el programa a
hacer
// Programa que muestra 'Hola mundo' por pantalla y finaliza

// Aqu se sitan todas las librerias que se vayan a usar con
#include,
// que se ver posteriormente
// Las librerias del sistema son las siguientes
#include <iostream>

// Funcin main
// Recibe: void
// Devuelve: int
// Funcin principal, encargada de mostrar "Hola Mundo",por pantalla

int main(void)
{
// Este tipo de lneas de cdigo que comienzan por '//' son
comentarios
// El compilador los omite, y sirven para ayudar a otros
programadores o
// a uno mismo en caso de volver a revisar el cdigo
// Es una prctica sana poner comentarios donde se necesiten,

std::cout << "Hola Mundo" << std::endl;

// Mostrar por std::cout el mensaje Hola Mundo y comienza una nueva
lnea

return 0;

// se devuelve un 0.
//que en este caso quiere decir que la salida se ha efectuado con
xito.
}

Mediante simple inspeccin, el cdigo parece enorme, pero el compilador lo nico que leer
para la creacin del programa es lo siguiente:
Ejemplo
#include <iostream>
int main(void){ std::cout << "Hola Mundo" << std::endl; return 0; }
Como se puede observar, este cdigo y el original no difieren en mucho salvo en los saltos de
lnea y que los comentarios, de los que se detallan posteriormente, estn omitidos y tan slo
ha quedado "el esqueleto" del cdigo legible para el compilador. Para el compilador, todo lo
dems, sobra.
O este otro, que es, en parte, como el lenguaje C, en su versin C99, es:
Ejemplo
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf( "Hola Mundo\n" );
return EXIT_SUCCESS;
// 'EXIT_SUCCESS' es una definicin que est dentro de 'stdlib.h'
// tambien funciona return 0
}

Nota: si se usa Windows, el cdigo es el mismo, pero debemos agregar un metodo mas para
que el programa se mantenga abierto y no se cierre la consola, cosa que en GNU, no es
necesaria por que la consola ya esta abierta (al mandar a ejecutar).
Para esto podemos usar cin.get() que nos permitira leer del teclado, por lo que el programa no
finalizara, hasta que el usuario pulse enter.


Ejemplo
#include <iostream>
int main(void)
{
std::cout << "Hola Mundo" << std::endl;
std::cin.get();
//con 'std::cin.get();' lo que se hace es esperar hasta que el
usuario pulse enter.
return 0;
}

Los pasos siguientes son para una compilacin en GNU o sistema operativo Unix. En
Windows tampoco es aplicable.
Con ctrl-x ctrl-s se guarda el archivo. Ahora para generar el ejecutable del programa se
compila con g++ de la siguiente forma:
$ g++ hola.cpp -o hola
Para poder ver los resultados del programa en accin, se ejecuta el programa de la siguiente
forma:
$./hola
Y a continuacin se debe mostrar algo como lo siguiente:
Hola Mundo
Comentarios[editar]
Cuando se escriben programas es muy til agregar comentarios que ayuden a explicar lo que
realiza un programa. En C++ se pueden utilizar tres tipos de comentarios: al estilo C, al estilo
C++ y usando preprocesador.
Los comentarios al estilo C se caracterizan por lo siguiente: comenzar el "bloque" de
comentarios con /* y terminar dicho "bloque" de comentarios con */
Ej:
/*

Este es un comentario al estilo C.
Todo lo escrito dentro de las etiquetas de apertura y cierre es un
comentario.
A estos comentarios se le llaman multilinea, logicamente
por el hecho de permitir varias lineas de comentarios.

*/
Si se usan este tipo de etiquetas de comentarios, hay que tener cuidado con el cierre (*/), por
que el compilador puede tomar todo el texto como comentario, o cerrar antes de lo deseado.
Usando el estilo de cdigo de C++ slo pueden ocupar una lnea como en el siguiente cdigo:
// Este es un comentario al estilo C++
Una buena prctica de programacin es pensar que se programa a sabiendas de que otro
programador, tal vez el lector mismo en un futuro, tenga que "desencriptar" qu quiso hacer
ah y por qu.
Otra posible forma de comentar cdigo es usando el preprocesador. Esto se detallar ms
adelante en profundidad, por ahora la parte til del preprocesador que interesa es la siguiente:
#if 0
Comentarios sobre el programa /parte del programa.
Pueden ocupar mltiples lneas.

Ms complicado de visualizar que los comentarios C/C++
#endif

Este tipo de comentarios se usan rara vez. Generalmente son difciles de localizar, incluso
para programadores experimentados que trabajan en papel, y son fciles de distinguir en casi
cualquier IDE. Es recomendable indicar que se tratan de comentarios, o directamente no
usarlos, salvo si son grandes cantidades de comentarios. Se ver ms adelante que tambin
puede tener otros usos.
Utilizacin de la consola o terminal[editar]
En los ejemplos anteriores se utilizaron 'std::cout'. 'std::cout' es un "objeto" que permite escribir
en la consola (la terminal en GNU/Unix/MacOSX), solo se puede utilizar gracias a que se ha
incluido definiciones de su uso con la lnea de cdigo '#include <iostream>'.
std::cout << ALGO;
Donde ALGO puede ser lo que sea que 'std::cout' sea capaz de mostrar por consola. Ms
adelante se trata ms sobre el en detalle y aclarando posibles dudas que ahora puedan surgir.
Tambin se utiliz 'std::endl', esto permite que el texto se escriba en una nueva lnea.
Un ejemplo ms completo sobre la escritura en consola es el siguiente. Ha de tenerse en
cuenta que se han eliminado algunos comentarios superfluos del primer programa debido a
que ahora se est tratando con ms detalle acerca del uso de imprimir texto en la consola:
Ejemplo
// Programa que muestra diversos textos por consola

// Las libreras del sistema usadas son las siguientes
#include <iostream>

// Funcin: main
// Recibe: void
// Devuelve: int
// Es la funcin principal encargada de mostrar por consola
diferentes textos
int main(void)
{
// Ejemplo con una nica lnea, se muestra el uso de std::cout y
std::endl
std::cout << "Bienvenido. Soy un programa. Estoy en una linea de
codigo." << std::endl;

// Ejemplo con una nica lnea de cdigo que se puede fraccionar
mediante el uso de '<<'
std::cout << "Ahora "
<< "estoy fraccionado en el codigo, pero en la consola me muestro
como una unica frase."
<< std::endl;

// Uso de un cdigo largo, que cuesta leer para un programador, y
que se ejecutar sin problemas.
// *** No se recomienda hacer lneas de esta manera, esta forma de
programar no es apropiada ***
std::cout << "Un gran texto puede ocupar muchas lineas."
<< std::endl
<< "Pero eso no frena al programador a que todo se pueda poner en
una unica linea de codigo y que"
<< std::endl
<< "el programa, al ejecutarse, lo situe como el programador quiso"
<< std::endl;

return 0; // Y se termina con xito.
}

Se reta a compilar este cdigo y a observar sus resultados. En este momento el lector est
capacitado para escribir programas que impriman por pantalla el mensaje que se quiera.
Atencin: Se hace hincapi en la posibilidad de que las palabras acentuadas no se puedan
mostrar en la consola. Depende completamente del compilador el que se pueda ver lo
siguiente:
std::cout << "programacin";
Con algunos compiladores, ver 'programacin', pero con otros puede ver incluso 'programaci
n'.

Advertencia: cout puede ser utilizado sin tener std:: de forma previa porque se puede
introducir una directiva, denominada 'using', que acomoda todos los cout. De otro modo habra
un error de compilador. Este tema se trata en detalle ms adelante.
using namespace std;
Sintaxis[editar]
Sintaxis es la forma correcta en que se deben escribir las instrucciones para el computador en
un lenguaje de programacin especfico. C++ hereda la sintaxis de C estndar, es decir, la
mayora de programas escritos para el C estndar pueden ser compilados en C++.
El punto y coma[editar]
El punto y coma es uno de los simblos ms usados en C, C++; y se usa con el fin de indicar
el final de una lnea de instruccin. El punto y coma es de uso obligatorio.

ejemplo

clrscr(); //Limpiar pantalla, funciona solo con la librera conio de
Borland C++
x = a + b;

string IP = "127.0.0.1"; // Variable IP tipo string
cout << IP << endl; // Devuelve 127.0.0.1

char Saludo[5] = "Hola"; // Variable Saludo tipo char
cout << Saludo[0] << endl; // Igual a H
cout << Saludo[1] << endl; // Igual a o
cout << Saludo[2] << endl; // Igual a l
cout << Saludo[3] << endl; // Igual a a


El punto y coma se usa tambin para separar contadores, condicionales e incrementadores
dentro de un sentencia for

ejemplo
for (i=0; i < 10; i++) cout << i;


Espacios y tabuladores[editar]
Usar caracteres extras de espaciado o tabuladores ( caracteres tab ) es un mecanismo que
nos permite ordenar de manera ms clara el cdigo del programa que estemos escribiendo,
sin embargo, el uso de estos es opcional ya que el compilador ignora la presencia de los
mismos. Por ejemplo, el segundo de los ejemplos anteriores se podra escribir como:
for (int i=0; i < 10; i++) { cout << i * x; x++; }
y el compilador no pondra ningn reparo.
Tipos primitivos[editar]
En un lenguaje de programacin es indispensable poder almacenar informacin, para esto en
C++ estn disponibles los siguientes tipos que permiten almacenar informacin numrica de
tipo entero o real:
Nombre Descripcin Tamao* Rango de valores*
char Carcter o entero pequeo 1byte
con signo: -128 to 127
sin signo: 0 a 255
short int
(short)
Entero corto 2bytes
con signo: -32768 a 32767
sin signo: 0 a 65535
int Entero 4bytes
con signo: -2147483648 a
2147483647
sin signo: 0 a 4294967295
long int
(long)
Entero largo 4bytes
con signo: -2147483648 a
2147483647
sin signo: 0 a 4294967295
bool
Valor booleano. Puede tomar dos valores:
verdadero o falso
1byte true o false
float Nmero de punto flotante 4bytes 3.4e +/- 38 (7 digitos)
double De punto flotante de doble precisin 8bytes 1.7e +/- 308 (15 digitos)
long double Long de punto flotante de doble precisin 8bytes 1.7e +/- 308 (15 digitos)

Los valores dependen de la arquitectura utilizada. Los mostrados son los que
generalmente se encuentran en una mquina tpica de arquitectura 32 bits.

El modificador long[editar]
El modificador long le indica al compilador que el tipo debe utilizar ms bits que los
normalmente utilizados por ejemplo si tenemos en una maquina de 32 bits como un Pentium
de Intel, normalmente de un int ocupara 32 bits, pero si al declararlo un entero le antecedemos
long el entero ocupa 64 bits, el siguiente cdigo muestra como utilizar este modificador:
int corto; // Entero de 32 bits
long int largo; // Entero de 64 bits
El Modificador short[editar]
Similar al anterior, pero indica que se deben utilizar menos bits. Por ejemplo, en un
computador de 32 bits, un short int ocupa 16 bits.
El Modificador unsigned[editar]
El modificador unsigned es utilizado nicamente con los enteros, su utilizacin permite utilizar
en los enteros nicamente la parte positiva,
int a; // Almacena valores entre -32768 y 32767
unsigned int a; // Almacena valores entre 0 y 65535
El Modificador register[editar]
Este modificador sobre una variable le indica al compilador que la variable debe almacenarse
en un registro en el compilador, que para el caso de los IA32, es un registro real de la propia
CPU, y por tanto el tiempo de acceso es ms rpido respecto a la memoria RAM. Hoy en da
apenas se utiliza este modificador, ya que los compiladores son capaces de determinar de
manera ptima la asignacin de registros a variables del programa.
El Modificador volatile[editar]
Al contrario que el modificador registrer, volatile obliga al compilador a forzar el cdigo
resultante de manera que la variable modificada con este modificador, sea almacenada
siempre en la memoria. El efecto que tiene es que cuando la variable se modifica con otro
valor, dicha variable se almacena directamente en memoria y no queda localizado el valor slo
en el registro de la CPU como pasaba en el caso de register o en condiciones normales. Un
uso muy comn en el que se suele emplear este modificador, es para acceder a variables que
estn siendo utilizadas por drivers o por perifricos, ya que si no declarsemos esta
propiedad, podra darse el caso que la CPU usase el valor de la variable, por lo que la cach
guarda el valor, y poco despus la CPU usase de nuevo dicha variable, pero como sta est
en cache, la CPU coge el valor que existe en la cach, que puede ser bien distinta al real
puesto que un posible perifrico puede haber modificado su valor.
El Modificador static[editar]
Dependiendo del entorno donde se declare la variable que la modifiquemos como static,
puede significar dos cosas muy distintas:
1. Si declaramos una variable static dentro del cuerpo de una funcin, lo que estamos
indicndole al compilador es que dicha variable sea inicializada solo una vez (la
primera vez que se llama a la funcin), y el resto de veces que se llame a la funcin,
la variable contendr el ltimo valor asignado. Esta variable slo podr ser visible
desde la funcin que declara dicha variable. Por ejemplo:
void mifuncion(){
static int i=0;
cout<<"En la entrada i vale "<<i<<endl;
for(int j=0;j<10;j++)
i++;
cout<<"En la salida i vale "<<i<<endl;
}
1. Si declaramos una variable static fuera del cuerpo de una funcin, lo que le estamos
indicando al compilador, es que dicha variable es privada para el modulo donde se
implementa el cdigo del contexto de la variable, es decir, que otro fichero objeto
binario, no podr tener acceso a dicha variable utilizando el modificador extern.
Ejemplo:
#import "prueba.h"

//variable privada para prueba.cpp
static int i=0;

void mifuncion(){
cout<<"En la entrada i vale "<<i<<endl;
for(int j=0;j<10;j++)
i++;
cout<<"En la salida i vale "<<i<<endl;
}
Tenga en cuenta que para este ltimo caso, usted podr acceder a la variable y desde
cualquier funcin que defina dentro de prueba.cpp, pero no tendr acceso desde cualquier
fichero objeto o fuente que no sea prueba.cpp
Espacio que ocupan la variables (en mquinas x86)[editar]
El espacio en bits que ocupan en la computadora una variable de este tipo se puede ver en la
siguiente tabla:
Tipo Nmero de Bits
char 8
short 16
int 32
long int 64
float 32
double 64
Rango de los Tipos Primitivos[editar]
El rango que puede almacenar los tipos primitivos en C++ es muy importante, para poder
saber cual es el rango de valores que puede almacenar un tipo es necesario conocer el
nmero de bits del tipo. El caso para enteros y para flotantes es distinto. Para enteros se debe
saber si el tipo es con signo o sin signo. si es sin signo el rango de valores que puede
almacenar es el siguiente:

Si el tipo es con signo el rango es el siguiente

Para ilustrar lo anterior supongamos que tenemos un entero de 16 bits sin signo, entonces el
rango de valores que puede almacenar es el siguiente:


Para obtener el rango de un entero de 32 bits con signo se puede realizar el siguiente calculo:

El caso de los nmeros flotantes es distinto y depende en gran manera del compilador y el
procesador que este utilizando. Sin embargo hoy en da la mayora de los compiladores y los
procesadores utilizan en estndar de la IEEE para representacin en coma flotante. Para
saber mas al respecto ver IEEE floating-point standard.
Tipos enumerados (enum)[editar]
Los tipos enumerados son un mecanismo usado en C y C++ con el objetivo de agrupar de
alguna manera constantes simblicas. Para definir tipos enumerados se usa la palabra
reservada enum.
Ejemplo 1
enum dias { domingo, lunes, martes, miercoles, jueves, viernes, sabado
};
En el ejemplo anterior se define por medio de enum el tipo enumerado dias, en el mismo
ejemplo se debe observar que dentro de la construccin se definen las constantes simblicas:
domingo, lunes, ... sabado; y que a las mismas el compilador les asignar respectivamente y
por defecto los valores: 0, 1, 2, 3, 4, 5, 6. Es decir, las constantes mencionadas pueden usarse
dentro del programa y este sabr a que valor hace referencia cada una de las mismas. Por
ejemplo, la instruccin: cout << domingo; desplegar 0 en la pantalla. El siguiente ejemplo
muestra como usar las constantes enumeradas en un ciclo for.
for (int d = domingo; d <= sabado; d++) cout << d;
En el siguiente ejemplo se define por medio de enum el tipo enumerado colores, en el mismo
se debe de observar la elinacin del comportamiento por defecto ya que a la primera
constante (gris) se le asigna en forma especfica el valor de 7, de tal manera que la siguiente
constante (grisoscuro) tendr un valor igual a 8 y la constante amarillo ser igual a 14.
Ejemplo 2
enum colores { gris = 7, grisoscuro, amarillo = 14 };
Tipos definidos por el usuario[editar]
En muchas ocasiones descubriremos que los tipos primitivos no bastan para llevar a cabo
ciertas tareas, debido a esto el lenguaje C, C++ da el soporte necesario para que el
programador defina sus propios tipos. Para definir tipos se usa la palabra reservada typedef.
Por ejemplo, si deseamos definir un tipo de dato llamado entero podemos usar la sintaxis:
typedef int entero;
Luego, podremos declarar variables, constantes y funciones del tipo entero. Por ejemplo,
entero edad = 33;
Un uso ms til y comn es el empleo de typedef para definir datos estructurados. Por
ejemplo, supongamos que deseamos definir un tipo estructurado llamado persona y que
contenga nombre, edad y sexo. Entonces podemos definir persona como:
typedef struct persona {
char nombre[32];
int edad;
char sexo;
};
Una vez que un tipo ya se ha definido, el mismo puede emplearse para declarar variables y
constantes de este. Por ejemplo, con la instruccin:
persona hombre;
se est declarando la variable hombre del tipo persona. Luego, para acceder a cada elemento
de la variable hombre usaremos un mecanismo conocido comodireccionamiento directo por
medio del carcter de punto ( . ). Por ejemplo, la edad de hombre se debe indicar como:
hombre.edad
Variables y constantes[editar]
Una variable, como su nombre lo indica, es un determinado objeto cuyo valor puede cambiar
durante el proceso de una tarea especfica. Contrario a una variable, una constante es un
determinado objeto cuyo valor no puede ser alterado durante el proceso de una tarea
especfica. En C, C++ para declarar variables no existe una palabra especial, es decir, las
variables se declarn escribiendo el tipo seguido de uno o ms identificadores o nombres de
variables. Por otro lado, para declarar constantes existe la palabra reservada const, as como
la directiva #define. A continuacin se muestran ejemplos de declaracin de variables y
constantes.
Variables Constantes Constantes
int a; const int a = 100; #define a 100
float b; const float b = 100; #define b 100
Notas:
A diferencia de las constantes declaradas con la palabra const los smbolos definidos
con #define no ocupan espacio en la memoria del cdigo ejecutable resultante.
El tipo de la variable o constante puede ser cualquiera de los listados en Tipos primitivos, o
bien de un tipo definido por el usuario.
Las constantes son usadas a menudo con un doble propsito, el primero es con el fin de hacer
ms legible el cdigo del programa, es decir, si se tiene (por ejemplo) la constante numerica
3.1416 y esta representa al nmero pi, entonces podemos hacer declaraciones tales como:
#define pi 3.1416

En este caso podremos usar la palabra pi en cualquier parte del
programa y el compilador se encargar de cambiar dicho simbolo por
3.1416.
o bien,
const pi = 3.1416;

En este otro caso podremos usar la palabra pi en cualquier parte del
programa y el compilador se encargar de cambiar
dicho smbolo por una referencia a la constante pi guardada en la
memoria.
Iteraciones y decisiones
Programacin en C++/Iteraciones y decisiones
Lo ms bsico Estructuras
Contenido
[ocultar]
1 Sentencias de decisin
2 Sentencia if
o 2.1 Sentencia switch
o 2.2 Operador condicional ternario ?:
3 Sentencias de iteracin
o 3.1 Sentencias For
o 3.2 Sentencia while
o 3.3 Sentencia do - while
4 Sentencias break y continue
o 4.1 break
o 4.2 continue
Sentencias de decisin[editar]

Estructura de control IF
DEFINICIN
Las sentencias de decisin o tambin llamadas de CONTROL DE FLUJO son estructuras de
control que realizan una pregunta la cual retorna verdadero o falso (evala una condicion) y
selecciona la siguiente instruccin a ejecutar dependiendo la respuesta o resultado.



En algn momento dentro de nuestros algoritmos, es preciso cambiar el flujo de ejecucin de
las instrucciones, es decir, el orden en que las instrucciones son ejecutadas. Muchas de las
veces tenemos que tomar una decisin en cuanto a que se debe ejecutar basndonos en una
respuesta de verdadero o falso (condicion).
La ejecucin de las instrucciones incluyendo una estructura de control como el condicional
funcionan de esta manera:
Las instrucciones comienzan a ejecutarse de forma secuencial (en orden) y cuando se
llega a una estructura condicional, la cual esta asociada a una condicion, se decide que
camino tomar dependiendo siempre del resultado de la condicion siendo esta falsa o
verdadera.
Cuando se termina de ejecutar este bloque de instrucciones se reanuda la ejecucin en la
instruccin siguiente a la de la condicional.
Sentencia if[editar]

La instruccin if es, por excelencia, la ms utilizada para construir estructuras de control de
flujo.
SINTAXIS
Primera Forma
Ahora bin, la sintaxis utilizada en la programacin de C++ es la siguiente:

if (condicion)
{
Set de instrucciones
}

siendo "condicion" el lugar donde se pondr la condicin que se tiene que cumplir para que
sea verdadera la sentencia y as proceder a realizar el "set de instrucciones" o cdigo
contenido dentro de la sentencia.

Segunda Forma
Ahora veremos la misma sintaxis pero ahora le aadiremos la parte "Falsa" de la sentencia:

if (condicion)
{
Set de instrucciones //PARTE VERDADERA
}
else
{
Set de instrucciones 2 //Parte FALSA
}

La forma mostrada anteriormente muestra la union de la parte "VERDADERA" con la nueva
secuencia la cual es la parte "FALSA" de la sentencia de decision "IF" en la cual esta
compuesta por el:
else
{
Set de instrucciones 2 //Parte FALSA
}
la palabra "else" o "De lo contrario" indica al lenguaje que de lo contrario al no ser verdadera o
no se cumpla la parte verdadera entonces realizara el "set de instrucciones 2".

EJEMPLOS DE SENTENCIAS IF...
Ejemplo 1:
if(numero == 0) //La condicion indica que tiene que ser igual a Cero
{
cout<<"El Numero Ingresado es Igual a Cero";
}

Ejemplo 2:
if(numero > 0) // la condicion indica que tiene que ser mayor a Cero
{
cout<<"El Numero Ingresado es Mayor a Cero";
}

Ejemplo 3:
if(numero < 0) // la condicion indica que tiene que ser menor a Cero
{
cout<<"El Numero Ingresado es Menor a Cero";
}

Ahora uniremos todos estos ejemplos para formar un solo programa mediante la utilizacin de
la sentencia "Else" e introduciremos el hecho de que se puede escribir en este espacio una
sentencia if ya que podemos ingresar cualquier tipo de cdigo dentro de la sentencia escrita
despus de un Else.
Ejemplo 4:
if(numero == 0) //La condicion indica que tiene que ser igual a Cero
{
cout<<"El Numero Ingresado es Igual a Cero";
}
else
{
if(numero > 0) // la condicion indica que tiene que ser mayor a
Cero
{
cout<<"El Numero Ingresado es Mayor a Cero";
}
else
{
if(numero < 0) // la condicion indica que tiene que ser menor a
Cero
{
cout<<"El Numero Ingresado es Menor a Cero";
}
}
}
Sentencia switch[editar]

switch es otra de las instrucciones que permiten la construccin de estructuras de control. A
diferencia de if, para controlar el flujo por medio de una sentenciaswitch se debe de combinar
con el uso de las sentencias case y break.
Notas: cualquier nmero de casos a evaluar por switch as como la sentencia default son
opcionales. La sentencia switch es muy til en los casos de presentacin de menus.
Sintaxis:
switch (condicin)
{
case primer_caso:
bloque de instrucciones 1
break;

case segundo_caso:
bloque de instrucciones 2
break;

case caso_n:
bloque de instrucciones n
break;

default: bloque de instrucciones por defecto
}
Ejemplo 1
switch (numero)
{
case 0: cout << "numero es cero";
}
Ejemplo 2
switch (opcion)
{
case 0: cout << "Su opcion es cero"; break;
case 1: cout << "Su opcion es uno"; break;
case 2: cout << "Su opcion es dos";
}
Ejemplo 3
switch (opcion)
{
case 1: cout << "Su opcion es 1"; break;
case 2: cout << "Su opcion es 2"; break;
case 3: cout << "Su opcion es 3"; break;
default: cout << "Elija una opcion entre 1 y 3";
}
Operador condicional ternario ?:[editar]
En C/C++, existe el operador condicional ( ?: ) el cual es conocido por su estructura
como ternario. El comportamiento de dicho operador es el mismo que una estructura if - then
- else del lenguaje BASIC (y de la funcin IIf de Visual Basic). El operador condicional ?: es
til para evaluar situaciones tales como:
Si se cumple tal condicin entonces haz esto, de lo contrario haz esto otro.
Sintaxis:
( (condicion) ? proceso1 : proceso2 )
En donde, condicion es la expresin que se evalua, proceso1 es la tarea a realizar en el
caso de que la evaluacin resulte verdadera, y proceso2 es la tarea a realizar en el caso de
que la evaluacin resulte falsa.
Ejemplo 1
int edad;
cout << "Cual es tu edad: ";
cin >> edad;
cout << ( (edad < 18) ? "Eres joven aun" : "Ya tienes la mayora de
edad" );
El ejemplo anterior podra escribirse de la siguiente manera:
int edad;
cout << "Cual es tu edad: ";
cin >> edad;
if (edad < 18) cout << "Eres joven aun";
else cout << "Ya tienes la mayora de edad";
Ejemplo 2
Vamos a suponer que deseamos escribir una funcin que opere sobre dos valores numricos
y que la misma ha de regresar 1 (true) en caso de que el primer valor pasado sea igual al
segundo valor; en caso contrario la funcin debe retornar 0 (false).
int es_igual( int a, int b)
{
return ( (a == b) ? 1 : 0 )
}
Sentencias de iteracin[editar]
DEFINICIN
Las Sentencias de Iteracin o Ciclos son estructuras de control que repiten la ejecucin de
un grupo de instrucciones. Bsicamente, una sentencia de iteracin es una estructura de
control condicional, ya que dentro de la misma se repite la ejecucin de una o ms
instrucciones mientras que una a condicin especifica se cumpla. Muchas veces tenemos que
repetir un nmero definido o indefinido de veces un grupo de instrucciones por lo que en estos
casos utilizamos este tipo de sentencias. en C++ los ciclos o bucles se construyen por medio
de las sentencias for, while y do - while. La sentencia for es til para los casos en donde se
conoce de antemano el nmero de veces que una o ms sentencias han de repetirse. Por otro
lado, la sentencia while es til en aquellos casos en donde no se conoce de antemano el
nmero de veces que una o ms sentencias se tienen que repetir.
Sentencias For[editar]
for(contador; final; incremento)
{
Codigo a Repetir;
}
donde:
1. contador es una variable numrica
2. final es la condicin que se evalua para finalizar el ciclo (puede ser independiente del
contador)
3. incremento es el valor que se suma o resta al contador
Hay que tener en cuenta que el "for" evalua la condicin de finalizacin igual que el while, es
decir, mientras esta se cumpla continuaran las repeticiones.
Ejemplo 1:
for(int i=1; i<=10; i++)
{
cout<<"Hola Mundo";
}
Esto indica que el contador "i" inicia desde 1 y continuar iterando mientras i sea menor o
igual a 10 ( en este caso llegar hasta 10) e "i++" realiza la sumatoria por unidad lo que hace
que el for y el contador se sumen. repitiendo 10 veces "HOLA MUNDO" en pantalla.
Ejemplo 2:
for(int i=10; i>=0; i--)
{
cout<<"Hola Mundo";
}
Este ejemplo hace lo mismo que el primero, salvo que el contador se inicializa a 10 en lugar
de 1; y por ello cambia la condicin que se evalua as como que el contador se decrementa en
lugar de ser incrementado.
La condicin tambin puede ser independiente del contador:
Ejemplo 3:
int j = 20;
for(int i=0; j>0; i++){
cout<<"Hola"<<i<<" - "<<j<<endl;
j--;
}
En este ejemplo las iteraciones continuaran mientras j sea mayor que 0, sin tener en cuenta el
valor que pueda tener i.
Sentencia while[editar]
while(condicion)
{
cdigo a Repetir
}

donde:
1. condicion es la expresin a evaluar
Ejemplo 1:
int contador = 0;

while(contador<=10)
{
contador=contador+1;
cout<<"Hola Mundo";
}
El contador Indica que hasta que este llegue a el total de 10 entonces se detendr y ya no se
realizar el cdigo contenido dentro de la sentencia while, de lo contrario mientras el
"contador" sea menor a 10 entonces el cdigo contenido se ejecutar desplegando hasta 10
veces "Hola Mundo" en pantalla.
Sentencia do - while[editar]
La sentencia do es usada generalmente en cooperacin con while para garantizar que una o
ms instrucciones se ejecuten al menos una vez. Por ejemplo, en la siguiente construccin no
se ejecuta nada dentro del ciclo while, el hecho es que el contador inicialmente vale cero y la
condicin para que se ejecute lo que est dentro del while es "mientras el contador sea mayor
que diez". Es evidente que a la primera evaluacin hecha por while la condicin deja de
cumplirse.
int contador = 0;

while(contador > 10)
{
contador ++;
cout<<"Hola Mundo";
}
Al modificar el segmento de cdigo anterior usando do tenemos:
int contador = 0;

do
{
contador ++;
cout<<"Hola Mundo";
}
while(contador > 10);
Observe cmo en el caso de do la condicin es evaluada al final en lugar de al principio del
bloque de instrucciones y, por lo tanto, el cdigo que le sigue al do se ejecuta al menos la
primera vez.
Sentencias break y continue[editar]
En la seccin (Sentencia switch) vimos que la sentencia break es utilizada con el propsito
de forzar un salto dentro del bloque switch hacia el final del mismo. En esta seccin
volveremos a ver el uso de break, salvo que esta ocasin la usaremos junto con las
sentecias for y la sentencia while. Adems, veremos el uso de la sentencia continue.
break[editar]
La sentencia break se usa para forzar un salto hacia el final de un ciclo controlado por for o
por while.
Ejemplo:
En el siguiente fragmento de cdigo la sentencia break cierra el ciclo for cuando la variable ( i )
es igual a 5. La salida para el mismo ser:
0 1 2 3 4
for (int i=0; i<10; i++) {
if (i == 5) break;
cout << i << " ";
}
continue[editar]
La sentencia continue se usa para ignorar una iteracin dentro de un ciclo controlado por for o
por while.
Ejemplo:
En el siguiente fragmento de cdigo la sentencia continue ignora la iteracin cuando la
variable ( i ) es igual a 5. La salida para el mismo ser:
0 1 2 3 4 6 7 8 9
for (int i=0; i<10; i++) {
if (i == 5) continue;
cout << i << " ";
}
Uso de break y continue junto con while
Los dos ejemplos anteriores se presentan en seguida, salvo que en lugar de for se hace uso
de while.
Nota: no deje de observar que la construccin del ciclo while para el caso de la sentencia
continue es diferente, esto para garantizar que el ciclo no vaya a caer en una iteracin infinita.
break
int i = 0;
while (i<10) {
if (i == 5) break;
cout << i << " ";
i++;
}
continue
int i = -1;
while (i<10) {
i++;
if (i == 5) continue;
cout << i << " ";
}
Estructuras
Programacin en C++/Estructuras
Iteraciones y decisiones Funciones
Contenido
[ocultar]
1 Estructuras de datos
o 1.1 Estructuras bsicas en C, C++
1.1.1 variables
o 1.2 Matrices o Arreglos
1.2.1 Matrices estticas
1.2.2 Acceso a los miembros de una matriz de datos:
1.2.3 Matrices dinmicas
o 1.3 Estructuras compuestas (struct, union, class)
1.3.1 Acceso a los miembros de una estructura
1.3.2 Estructuras anidadas
1.3.3 Herencia
1.3.4 Estructura de campos de bits
o 1.4 union: Sintaxis general
o 1.5 class: sintaxis
o 1.6 struct vs. class
Estructuras de datos[editar]
Las estructuras de datos se emplean con el objetivo principal de organizar los datos
contenidos dentro de la memoria del ordenador. As, nuestra primera experiencia con
estructuras comienza desde el momento mismo en que usamos en nuestros programas
variables de tipos primitivos (char, short, int, float, etc). A la memoria del ordenador se le
puede considerar como un gran bloque compuesto por una serie de BYTES dispuestos
secuencialmente uno detrs de otro. por ejemplo, si un ordenador posee una memoria de
128MB (128 megas) entonces se le puede leer o escribir desde el BYTE 0 hasta el BYTE
128MB - 1 ( 0000000H .. 7FFFFFFH ).

La idea de ver la memoria como un serie de bytes es buena, sin embargo no es suficiente ya
que en la misma podemos guardar nmeros, cadenas de caracteres, funciones, objetos, etc.
de tal manera que surge la necesidad de establecer los mecanismos adecuados para dar
cuenta de la forma, tamao y objetivo de los datos almacenados. Segn el tipo de
microprocesador, estos tienen la capacidad para manipular o direccionar estructuras
compuestas por uno, dos, cuatro, etc, bytes; de donde se derivan los tipos que comunmente
se conocen como: BYTE, WORD, DWORD, QWORD y TWORD.

La estructura mnima de informacin manipulable en un sistema de memoria de ordenadores
es el BIT el cual se agrupa normalmente en bloques de 8 para formar un BYTE. Cabe
mencionar que los BITS no son direccionables directamente, sino a travez de compuertas
AND, OR, NOT, XOR, mismas que en C,C++ se escriben como &, |, ~ y ^ conocidos como
"Bitwise operators".

En C,C++ existe una serie de estructuras bsicas o tipos primitivos, los cuales pueden ser
usados por el programador para declarar variables, y tambin son el fundamento sobre el cual
se crean estructuras complejas. El tamao de los tipos primitivos no es estndar ya que los
mismos dependen de factores tales como:
Tipo del microprocesador
El compilador
Sin embargo, en la actualidad, la mayoria de compiladores de C,C++ soportan los siguientes
tipos con la longitud indicada:
Estructuras bsicas en C, C++[editar]
Tipos primitivos
Nombre comn Nombre C Longitud Procesador 64 bits
BYTE char 8 bits 8 bits
WORD short 16 bits 16 bits
DWORD int 32 bits 32 bits
DWORD long 32 bits 64 bits
DWORD float 32 bits 32 bits
QWORD double 64 bits 64 bits
TWORD long double 80 bits 128 bits

Nota: en el lenguaje C,C++ existe el operador sizeof(), con el cual se puede obtener el
tamao (nmero de bytes) ocupados por un tipo especfico. Por ejemplo,sizeof(int) regresa el
nmero de bytes ocupados por los datos de tipo int.
variables[editar]
En C, C++ la sintaxis para declarar variables es:
tipo id1 [, id2 ...] ;

donde, tipo se refiere a uno de los tipos mostrados en la tabla anterior; id1 es el nombre con
el cual se identificar a la variable. Observe que si se quiere declarar ms de una variable en
una lnea de instruccin, las mismas deben separarse por medio de una coma.
Ejemplos:
char c; // La variable c es una variable char
int i; // La variable i es una variable int
float f; // La variable f es una variable float
int x,y,z; // Las variables x,y,z son todas variables int, y
declaradas a la vez

De acuerdo con la tabla anterior y segn las instrucciones anteriores, con la primera, o sea (
char c;), se le est indicando al ordenador que reserve en la memoria un espacio de tipo char
(4 bits) y que el mismo ser identificado bajo el nombre de c. La segunda instruccin ( int i;) le
indica al ordenador que reserve en la memoria un espacio de tipo int (16 bits) y que el mismo
ser identificado bajo el nombre de i. Luego, la instruccin ( float f;) le indica al ordenador que
reserve en la memoria un espacio de tipo float (32 bits) y que el mismo ser identificado bajo
el nombre de f. Por ltimo, se le indica al compilador que reserve espacio para otras tres
variables enteras identificadas como: x, y, z. As, se puede dar cuenta cmo los tipos
primitivos sirven con el propsito de estructurar los datos dentro de la memoria y con la idea
de referirnos a los mismos mediante nombres usamos identificadores de variables.
Matrices o Arreglos[editar]
Una Matriz (en ingls, array, tambin denominado arreglo) es una
estructura usada para agrupar bajo un mismo nombre
listas de datos de un mismo tipo.
El tipo de matriz puede ser cualquiera, sin embargo cada componente tiene que ser del mismo
tipo. En C estndar solamente da soporte para matrices estticas, mientras que con C++ se
pueden crear matrices dinmicas pudiendo usar la librera estndar de plantillas (STL).
Matrices estticas[editar]
Una matriz esttica es una estructura cuyo tamao es determinado en tiempo de compilacin,
es decir, una vez establecido el tamao de la matriz sta no podr cambiarse durante el
tiempo de ejecucin. En C, C++ para declarar un arreglo esttico de datos se emplea la
sintaxis:
tipo identificador[ [tamao] ] [ = { lista de inicializacin } ] ;
donde,
tipo se refiere al tipo de datos que contendr la matriz. El tipo puede ser cualquiera de los
tipos estndar (char, int, float, etc.) o un tipo definido por el usuario. Es ms, el tipo de la
matriz puede ser de una estructura creada con: struct, union y class.
identificador se refiere al nombre que se le dar a la matriz.
tamao es opcional e indica el nmero de elementos que contendr la matriz. Si una
matriz se declara sin tamao, la misma no podr contener elemento alguno a menos que
en la declaracin se emplee una lista de inicializacin.
lista de inicializacin es opcional y se usa para establecer valores para cada uno de los
componentes de la matriz. Si la matriz es declarada con un tamao especifco, el nmero
de valores inicializados no podr ser mayor a dicho tamao.
Ejemplos:
int intA[5];
long longA[5] = { 1, 2, 3, 4, 5 };
char charA[] = { 'a', 'b', 'c' };
Acceso a los miembros de una matriz de datos:[editar]
En orden de acceder a los miembros de una matriz se debe indicar el nombre de la matriz
seguido de dos corchetes, dentro de los cuales se debe especificar el ndice del elemento
deseado. Se debe aclarar que los ndices son nmeros o expresiones enteras y que en C,
C++ estos tienen un rango permitido de 0 a T-1 ( T = tamao de la matriz ).
Ejemplos: dadas las matrices intA, charA, longA ( ejemplo anterior )
intA[0] = 100; // establece el valor del elemento 0 de intA a 100.

charA[3] = 'O'; // establece el valor del elemento 3 de charA a 'O'.

cout << longA[0]; // muestra por pantalla el elemento 0 de longA, que
es longA[0].
Matrices dinmicas[editar]
Una matriz dinmica es una estructura compleja y, ya que C estndar no da el soporte para
operar con estos tipos de estructuras, le corresponde al programador crear los algoritmos
necesarios para su implementacin. Crear lista dinmicas de datos en C estndar no es una
tarea para programadores inexpertos, ya que para lograr tal objetivo se necesita tener
conocimentos solidos acerca de los punteros y el comportamiento de los mismos. Los
usuarios de C++ pueden auxiliarse de la librera estndar de plantillas, conocidas por sus
siglas en ingles como STL.
Estructuras compuestas (struct, union, class)[editar]
Con base en los tipos bsicos mostrados arriba, se pueden crear nuevos tipos con estructuras
compuestas por uno o ms de uno de los tipos mencionados. En C, C++ en orden de crear
nuevas estructuras se emplean la palabras reservadas struct, union y class.
struct: esta orden se emplea para agrupar variables de tipos iguales o diferentes en un
solo registro, con la misma se pueden crear estructuras annimas, estructuras con
nombre, y un tipo especial de estructura conocida como bit-fields ( banderas o campos de
bits ).
union: una union es similar a una struct, salvo que en una estructura creada con union los
campos o variables comparten una direccin de almacenamiento comn.
class: una clase es una estructura en donde se agrupan variables y funciones, la misma
es usada en Programacin Orientada al Objeto. Las clases no son soportadas por el C
estndar.
Nota: tanto las estructuras como las uniones y las clases pueden ser
annimas, pero lo ms
recomendable es darle a las mismas un nombre. Si una estructura, union o
clase posee
nombre, esta pueden ser empleadas para declarar variables de la misma y,
lo ms importante,
puede ser usada para el paso de parmetros a funciones.

Sintaxis general: struct
struct [ <nombre tipo de estructura > ] {
[ <tipo> <nombre-variable[, nombre-variable, ...]> ] ;
[ <tipo> <nombre-variable[, nombre-variable, ...]> ] ;
...
} [ <variables de estructura> ] ;
Nota: recuerde que lo que se muestra entre corchetes es opcional.

struct: Sintaxis ( variacin uno, estructura annima )
De acuerdo con la sintaxis general de la orden struct es posible crear estructuras de datos
annimas. Solamente hay que tener en cuenta que en una declaracin annima se debe
definir al menos una variable al final de la declaracin. Por ejemplo, con el siguiente fragmento
de cdigo:
struct { int a, b; } p1;
se declara y define la variable estructurada p1, misma que se compone por los
miembros a y b; ambos del tipo int. Ahora bien, la sintaxis mostrada arriba no es tan comn ni
conveniente, ya que con la misma solamente se esta creando una variable estructurada pero
no un nuevo tipo. Es decir, si desearamos tener otra variable que tuviera las mismas
caracteristicas que posee la variable p1, necesitariamos escribir exactamente la misma
instruccin, salvo que cambiando el nombre de la variable. Por ejemplo:
struct { int a, b; } p2;
Por supuesto, en una misma lnea de instruccin podemos definir ms de una variable.
Ejemplo:
struct { int a, b; } p1, p2;
Entonces, para crear nuevos tipos con struct deberemos de modificar la sintaxis mostrada en
los ejemplos anteriores.

Sintaxis: struct ( variacin dos, estructura con nombre )
Observe que, la sintaxis para declarar estructuras con nombre es bastante parecida a la
sintaxis para declarar estructuras annimas; salvo que una declaracin de estructura con
nombre se debe especificar el nombre deseado para la misma. Adems, en una declaracin
de estructura con nombre la o las variables definidas al final de la misma son opcionales.
Ejemplos:
struct pareja { int a, b; } p1;
En el fragmento de cdigo anterior se declara la estructura identificada como pareja, misma
que se compone de los miembros a y b, ambos de tipo int. En el mismo ejemplo, se define la
variable p1; la cual es una variable estructurada de tipo pareja.
Una vez que una estructura con nombre ha sido creada, la misma puede ser usada para
declarar cualquier nmero de variables. Por ejemplo, en el siguiente fragmento de cdigo se
crea la estructura tiempo compuesta por los miembros hora, minuto y segundo; todos del tipo
int. En el mismo ejemplo, se declaran las variables t1 y t2.
/* declaracin de estructura tiempo */
struct tiempo { int hora, minuto, segundo; };

/* declaracin de variables de tipo tiempo */
struct tiempo t1, t2;
Nota: en C++ puede obviarse la palabra struct a la hora de declarar variables. As, en C++ la
lnea de instrucin struct tiempo t1, t2; ( del ejemplo anterior) puede escibirse como: tiempo
t1, t2;
Acceso a los miembros de una estructura[editar]

En orden de poder leer o escribir uno de los miembros de una variable estructurada, se debe
usar el operador de acceso ( . ); o sea, el nombre de la variable seguida por un punto seguido
por el nombre del miembro o componente deseado de la estructura. Por ejemplo, para
acceder a los miembros de la variable t1 (mostrada arriba) podemos hacerlo de la siguiente
manera:
t1.hora = 12;
t1.minuto = 0;
t1.segundo = 0;

printf ("%i\n", t1.hora);
cout << t1.minuto << endl;
Estructuras anidadas[editar]

Los miembros de una estructura pueden ser ellos mismos, otra estructura previamente
identificada, o bien una estructura annima. Por ejemplo, en el siguiente fragmento de cdigo,
se crean las estructuras pareja y pareja2. Obsrvese cmo dentro de los miembros de
pareja2, se declara el miembro X, que a su vez es una estructura del tipo pareja. Luego, las
variables declaradas a raz de la estructura pareja2 poseern los miembros
variables a y b heredados de pareja, y c.
struct pareja { int a, b ; };
struct pareja2 { struct pareja X; int c; } P3;
Ahora bien, para acceder a los miembros de una estructura dentro de otra estructura se
emplea el mismo mecanismo de acceso (el punto). Por ejemplo, para desplegar el
miembro a de la variable P3 declarada en el ejemplo anterior, lo haremos ms o menos as:
printf( "%i\n", P3.X.a );
Herencia[editar]

El trmino herencia se usa con gran frecuencia en Programacin Orientada a Objetos, y se le
relaciona principalmente con las clases. Sin embargo, la herencia est presente siempre y
cuando una estructura "struct", "union" o "class" posea a otra estructura. En ese sentido, en
C++ se presentan dos tipos de herencia:
herencia por agregacin o composicin.
herencia por extensin.
Por ejemplo, en la definicin de las estructuras pareja y pareja2 del ejemplo anterior, se dice
que pareja2 hereda por composicin todos los miembros de pareja. Ahora, en el siguiente
ejemplo se usa la sintaxis para que la estructura pareja2 herede por extensin los miembros
de pareja:
// solo C++
struct pareja { int a, b ; };
struct pareja2 : pareja { int c; } P3;
Con esta forma de herencia, la estructura pareja2 hereda de pareja los miembros a y b, y
adems agrega un miembro c. Y a diferencia del ejemplo anterior, para acceder a alguno de
sus miembros heredados, basta con utilizar el mecanismo de acceso (el punto).
// solo C++
cout << P3.a << P3.b ;
Estructura de campos de bits[editar]

Un campo de bit es un elemento de una estructura definido en terminos de bits.
Usando un tipo especial de definicin de struct, se pueden declarar elementos de
estructura con rangos de 1 a 16 de largo (dependiendo de la arquitectura de la PC y
del compilador, el rango para una estructura de campos de bits puede ser de 1 a 16, 1
a 32, 1 a 64).
Antes de ver un ejemplo del uso de struct para crear estructuras de campos de bits,
consideremos el caso en donde se tiene una variable del tipo short (16 bits) y que para la
misma se desea que los bits tengan significados especficos. Digamos que el primer bit
servir para controlar alguna condicin; los siguientes cuatro bits, o sea del segundo al
quinto bit, controlarn otra condicin; el bit 6 tendr otra funcin; y el resto, o sea del
sptimo al decimosexto bit se emplearn para controlar otra condicin. De tal manera que
si queremos, por ejemplo, saber si el primer bit de la variable tiene almacenado un 1 o un
0, podemos emplear la siguiente sintaxis:
int X = 123;
int r = X & 1;
la cosa parece sencilla, pero ahora consideremos el caso en el cual deseamos saber cual
es el valor contenido por el grupo de bits ( segundo al quinto ), entonces nos daremos
cuenta que no basta con una prueba mediante AND ( X & 1 ), sino que hay que realizar
otros pasos.
Precisamente, para problemas como el planteado arriba es por los que los lenguajes C y
C++ soportan las estructuras de campos de bits. Por ejemplo, la estructura
struct campo_de_bit {
int bit_1 : 1;
int bits_2_a_5 : 4;
int bit_6 : 1;
int bits_7_a_16 : 10;
} bit_var;

corresponde a la siguiente coleccin de campos bits:





El mecanismo de estructuras de campos de bits soportado por C,C++ es una
herramienta til y poderosa, sobre todo en programacin de bajo nivel; ya que
mediante el mismo es posible aislar y dar nombres a todos y cada uno de los bits de
un dato, y tambin crear en un mismo campo grupos de bits (como se mostr arriba).
Ahora bien, no hay que olvidar que la estructura mnima de informacin en un sistema
de memoria de un PC es el bit, y que para aislar a cada uno de estos se puede
emplear el operador AND ( &, en C ), pero mediante el mecanismo mencionado el
compilador genera los algoritmos necesarios para llevar a cabo el aislamiento de los
bits. Por ejemplo, para escribir y leer bit identificado como bit_1 de la
variable bit_var del ejemplo anterior, podemos emplear las siguientes instrucciones:
bit_var.bit_1 = 1;
printf("%i\n", bit_var.bit_1 );

Nota: acerca de las estructuras de campos de bits hay que aclarar que, aunque cada
uno de los campos de la estructura pueden declararse como enteros con signo o
enteros sin signo, la misma no tendr una longitud mayor a un entero largo.

union: Sintaxis general[editar]
union [ <nombre tipo de union > ] {
<tipo> <lista de variables>;
} [ <variables de union> ] ;

De la misma manera que con la orden struct, con la orden union se pueden crear
estructuras con nombre y estructuras sin nombre.
El mecanismo de acceso a los miembros de una union es igual al mecanismo de
acceso a los miembros de una struct.
Los miembros de una union comparten un espacio de almacenamiento comn.
En una union, el compilador reserva el espacio de almacenamiento para la misma
de acuerdo con el tipo de la variable de mayor tamao.

Ejemplo: union annima
union { short a; long b; } u1;

En el ejemplo anterior se declara la variable u1, la cual es una estructura tipo union. El
espacio de almacenamiento para la variable a es compartido por la variableb, en
consecuencia, al escribir sobre cualquiera de estas dos variables se altera el
contenido de ambas.

Ejemplo: union con nombre

union ux { short a; long b; } u1;

En el ejemplo anterior se declara la variable u1, la cual es una estructura tipo union. El
espacio de almacenamiento para la variable a es compartido por la variableb. Es
decir, el compilador reservar espacio en la memoria para la variable de mayor
tamao (que para ste caso es b ). Ahora bin, suponiendo que en su equipo el
tipo long ocupa 32 bits y que el tipo short ocupa 16 bits, entonces la
variable a ocupar solamente los 16 bits menos significativos, mientras que la
variable bocupar todo el espacio, o sea los 32 bits; Observe que en la sintaxis se ha
especificado el nombre ux, mismo que puede ser empleado para declarar cualquier
nmero de variables de la union. Por ejemplo, a continuacin se declaran las variables
u2 y u3 del tipo union ux creado en el ejemplo anterior.
union ux u2, u3;

class: sintaxis[editar]
<classkey> <classname> [<:baselist>] { <member list> } [lista de
variables] ;
<classkey> es una de las palabras "class", "struct", o "union".
<baselist> lista de clas(es) base de donde se deriva esta clase. <baselist> es
opcional.
<member list> declara los datos miembros y funciones miembros de la clase.
[lista de variables] esta entrada es opcional y se usa para instanciar variables u
objetos de esta clase.

Nota: Dentro de una clase,
los datos son llamados "datos miembros"
las funciones son llamadas "funciones miembros".
El mecanismo para acceder a los miembros de una class es igual que aquel
utilizado para acceder a los miembros de una struct

Las clases son algo as como "super" estructuras capaces de agrupar no solo datos
miembros sino tambin funciones miembros. En el lenguaje comn a los datos
miembros de una clase se les conoce como atributos; mientras que a las funciones
miembros de una clase se les llama mtodos. Normalmente, los mtodos se emplean
para leer o escribir los atributos. Es decir, la norma general es no permitir el acceso
directo a los atributos de una clase, con la idea de aumentar la seguridad de los datos.
En seguida se mostrar el cdigo para crear la clase Pareja, misma que poseer los
atributos a y b, y los mtodos setA(), setB(); getA(), getB(), y mostrar();
class Pareja {
int a, b;
public:
void setA(int n) { a = n; }
void setB(int n) { b = n; }
int getA() { return a; }
int getB() { return b; }
void mostrar() {
cout << "a = " << a << "; b = " << b << endl;
}
} p1;

Nota: por omisin, los miembros de una clase son privados, lo cual significa que los
objetos instanciados de dicha clase no tendrn acceso a los mismos. As, en el
ejemplo anterior se est creando la clase Pareja, y al mismo tiempo el objeto p1.
Luego, para leer o escribir los atributos de p1 se debe hacer a traves de los mtodos
definidos con tal objetivo. Por ejemplo, con el siguiente fragmento de cdigo se
establecen respectivamente a 100 y a 200 los atributos a y b; y posteriormente se
despliegan por medio del mtodo mostrar().
p1.setA(100);
p1.setB(200);
p1.mostrar();
struct vs. class[editar]
Esta seccin no pretende ensear que el uso de la palabra struct es lo mismo que
usar la palabra class. Sin embargo, como ya se mencion en una seccin anterior a
esta, las estructuras (struct) pueden extenderse de otras y heredar todos los
miembros de la estructura base. Otro punto que se demostrar aqu es el hecho de
que las estructuras en C++ (no en C estndar) pueden contener miembros funciones.
Por supuesto, el compilador trata a una struct de una forma diferente que a
una class. Entre algunas de las diferencias que se pueden mencionar respecto a las
estructuras contra las clases son:
Los miembros de una struct son pblicos por defecto, mientras que los miembros
de una class son privados por defecto.
Los parmetros-argumentos struct se pasan normalmente por copia, los
parmetros-argumentos class se pasan normalmente por referencia.
// Este programa ha sido probado en Dev-C++, Borland C++ y
Code::Blocks

#include <iostream>

using namespace std;

// estructura tipo clase base
struct Par {

int a, b;

// constructor base
Par() { a = b = 0; }

// destructor base
~Par() { cout << "hecho..." << endl; }

void setA(int n) { a = n; }
void setB(int n) { b = n; }

void mostrar() {
cout << "a = " << a << ", b = " << b << "; suma = " <<
a+b << endl;
}
};

// estructura tipo clase hija
// ParHijo es una extensin de Par, y por lo tanto hereda los
miembros de Par
struct ParHijo : Par {

// constructor del hijo
ParHijo(int a, int b) {
this->a = a;
this->b = b;
}
};


// prueba
void test00() {
ParHijo p1(100, 200); // p1 es instancia de ParHijo
p1.mostrar(); // se enva mensaje al mtodo
mostrar() de p1
}

// funcion principal
int main()
{
test00();
cin.get();
return 0;
}
Funciones
Programacin en C++/Funciones
Estructuras Streams
Contenidos
[ocultar]
1 Funciones
o 1.1 Definiendo una funcin
o 1.2 Parmetros
o 1.3 Llamar a una funcin
o 1.4 Funciones void
o 1.5 Funciones anidadas
o 1.6 Funciones de tipo puntero (*)
o 1.7 Variables estticas y automticas
o 1.8 Parmetros constantes
o 1.9 Parmetros con valor por defecto
o 1.10 Parmetros de tipo puntero
o 1.11 Parmetros estructurados
o 1.12 Funciones sobrecargadas
o 1.13 Nmero variable de parmetros
Funciones[editar]
Definiendo una funcin[editar]

Una funcin es un conjunto de lneas de cdigo que realizan una tarea especfica y puede
retornar un valor. Las funciones pueden tomar parmetros que modifiquen su funcionamiento.
Las funciones son utilizadas para descomponer grandes problemas en tareas simples y para
implementar operaciones que son comnmente utilizadas durante un programa y de esta
manera reducir la cantidad de cdigo. Cuando una funcin es invocada se le pasa el control a
la misma, una vez que esta finaliz con su tarea el control es devuelto al punto desde el cual
la funcin fue llamada.


<tipo> [clase::] <nombre> ( [Parmetros] )
{
cuerpo;
}
Ejemplo de una funcin
Para comenzar, vamos a considerar el caso en el cual se desea crear la funcin cuadrado(),
que deber devolver el cuadrado de un nmero real (de punto flotante), es decir, cuadrado()
aceptar nmeros de punto flotante y regresar una respuesta como nmero flotante.
Nota: aunque para la funcin que veremos el tipo de retorno coincide con el tipo de parmetro
pasado, algunas veces las cosas pueden cambiar, es decir, no es obligatorio que una funcin
reciba un parmetro de un tipo y que tenga que regresar una respuesta de dicho tipo.
// regresar el cuadrado de un nmero
double Cuadrado(double n)
{
return n*n;
}
Parmetros[editar]
Normalmente, las funciones operan sobre ciertos valores pasados a las mismas ya sea como
constantes literales o como variables, aunque se pueden definir funciones que no reciban
parmetros. Existen dos formas en C++ de pasar parmetros a una funcin; por referencia o
por valor. El hecho es que si en una declaracin de funcin se declaran parmetros por
referencia, a los mismos no se les podr pasar valores literales ya que las referencias apuntan
a objetos (variables o funciones) residentes en la memoria; por otro lado, si un parmetro es
declarado para ser pasado por valor, el mismo puede pasarse como una constante literal o
como una variable. Los parmetros pasados por referencia pueden ser alterados por la
funcin que los reciba, mientras que los parmetros pasados por valor o copia no pueden ser
alterados por la funcin que los recibe, es decir, la funcin puede manipular a su antojo al
parmetro, pero ningn cambio hecho sobre este se reflejar en el parmetro original.
Parmetros por valor
La funcin cuadrado() (ver arriba) es un clsico ejemplo que muestra el paso de parmetros
por valor, en ese sentido la funcin cuadrado() recibe una copia del parmetro n. En la misma
funcin se puede observar que se realiza un calculo ( n*n ), sin embargo el parmetro original
no sufrir cambio alguno, esto seguir siendo cierto an cuando dentro de la funcin hubiera
una instruccin parecida a n = n * n; o n*=n;.
Parmetros por referencia
Para mostrar un ejemplo del paso de parmetros por referencia, vamos a retomar el caso de
la funcin cuadrado, salvo que en esta ocasin cambiaremos ligeramente la sintaxis para
definir la misma. Veamos:
// regresar el cuadrado de un nmero
double cuadrado2(double &n)
{
n *= n;
return n;
}
Al poner a prueba las funciones cuadrado() y cuadrado2() se podr verificar que la primera de
estas no cambia el valor del parmetro original, mientras que la segunda s lo hace.
Llamar a una funcin[editar]
para llamar a la funcin cuadrado() vista anteriormente, podemos emplear:
cout << cuadrado(25);
cout << cuadrado(X);
R = cuadrado(X); // guardar en R el cuadrado de X
Funciones void[editar]
Bajo ciertas circunstancias se desear escribir funciones que no regresen valor alguno (esto
sera algo parecido a escribir procedures en Pascal) y para ello podemos declarar a la funcin
como void. La palabra reservada void es utilizada para declarar funciones sin valor de retorno
y tambin para indicar que una funcin especfica no requiere de parmetros. Por ejemplo, la
funcin pausa() que se ver en seguida, no devolver valor alguno y la misma no requiere de
parmetros.
// esta funcin requiere de la librera iostream
void pausa(void)
{
cout << "Por favor presione <Enter> HOLA...";
cin.get();
cin.ignore(255, '\n'); // rechazar caracteres introducidos antes
de <Enter>
}
Notas: se debe de aclarar que el uso de la palabra void dentro de los parentesis es opcional
al momento de declarar una funcin. As, la funcin pausa() podra haberse declarado
como void pausa(), y la misma puede invocarse como: pausa();.
Funciones anidadas[editar]
A diferencia de Pascal, el lenguaje C, C++ no permite anidar funciones, sin embargo, dentro
de una funcon puede existir la llamada a una o ms funciones declaradas previamente.
Funciones de tipo puntero (*)[editar]
En muchas ocasiones se desea que ciertas funciones regresen una referencia o puntero hacia
un tipo (sea este estructurado o no) especfico de dato en lugar de un valor especfico. En
tales casos, la funcin se deber declarar como para que regrese un puntero. Por ejemplo,
supongamos que deseamos crear una funcin para convertir un nmero entero en notacin
decimal a una cadena de caracteres en forma de nmeros binarios, luego, la funcin
mencionada podra escribirse para que reciba el nmero entero como parmetro y regrese un
puntero a una cadena de caracteres conteniendo la conversin. Para ser ms puntuales,
vamos a escribir un programa en donde se ver la funcin binstr(), y cuyo objetivo ser
precisamente convertir nmeros decimales en cadenas binarias.
Nota: observe que en la sintaxis para declarar funciones tipo puntero se debe de poner el
smbolo * despues del tipo y antes del nombre de la funcin que se est declarando. Esto se
puede ver en el programa, ya que la funcin binstr se declara como: char *binstr(unsigned
int);
#include <iostream>
#include <string.h>

using namespace std;

// declaracin de prototipo
char *binstr(unsigned int);

// punto de prueba
int main()
{
int n = 128;
cout << "decimal = " << n << ", binario = " << binstr(n) << endl;
cin.get();
}

// definicin de funcin binstr()
// nota: esta funcion requiere de la librera estndar string
char *binstr(unsigned int n)
{
static char buffer[65];
int i = 0;

strcpy(buffer, "0");

if (n > 0) {
while (n > 0) {
buffer[i] = ( n & 1 ) + '0';
i++;
n >>= 1;
}
buffer[i] = '\0';
strrev(buffer);
} // fin (n > 0)
return buffer;
}
Variables estticas y automticas[editar]
Dentro de una funcin, las variables y/o constantes pueden ser declaradas como: auto (por
omisin) o como static. Si una variable dentro de una funcin es declarada como esttica
significa que la misma retendr su valor entre las llamadas a la funcin. Por otro lado, la
variables automticas pierden su valor entre las llamadas. En el programa anterior puede
verse que el arreglo de caracteres (buffer[65]) se ha declarado como esttico para garantizar
que dicho buffer retenga los datos an despues de que la funcin termine. En el mismo
ejemplo, si el buffer no se declara como esttico, el contenido del mismo podra ser destruido
al salir de la funcin y los resultados obtenidos podran ser no deseados.
Parmetros constantes[editar]
Los parmetros usados por una funcin pueden declararse como constantes ( const ) al
momento de la declaracin de la funcin. Un parmetro que ha sido declarado como constante
significa que la funcin no podr cambiar el valor del mismo ( sin importar si dicho parmetro
se recibe por valor o por referencia ).
Ejemplo:
int funcionX( const int n );
void printstr( const char *str );
Parmetros con valor por defecto[editar]
Los parmetros usados por una funcin pueden declararse con un valor por defecto. Un
parmetro que ha sido declarado con valor por defecto es opcional a la hora de hacer la
llamada a la funcin. Ejemplo: Dada la funcin:
void saludo( char* mensaje = "Hola sudafrica 2010" );
la misma puede ser invocada como:
saludo(); // sin parmetro
saludo("Sea usted bienvenido a C++"); // con parmetro
Para ver un ejemplo ms, vamos a considerar el caso de la funcin binstr() del programa
funciones01. Ahora, vamos modificar dicha funcin, salvo que esta ocasin nos interesa que la
misma sirva para convertir nmeros decimales en cadenas numricas y cuya base de
conversin sea pasada como parmetro. Es decir, la funcin de la que estamos hablando
podr convertir nmeros decimales a: binario, octal, decimal, hexadecimal, etc.; y la nica
condicin ser que la base indicada est entre el 2 y el 36, inclusive.
Nota: Ya que la funcin servir para convertir nmeros a cualquier representacin la
nombraremos como numstr() en lugar de binstr(). Si la funcin es invocada sin el parmetro
base regresar una cadena de digitos decimales.
#include <iostream>
#include <stdlib.h>

using namespace std;

// declaracin de prototipo
char *numstr(unsigned int, const int base = 10);

// punto de prueba
int main()
{
int n = 128;
cout << "decimal = " << n << ", binario = " << numstr(n, 2) <<
endl;
cout << "decimal = " << n << ", octal.. = " << numstr(n, 8) <<
endl;
cin.get();
}

// definicin de funcin numstr()
// nota: esta funcion requiere de la librera stdlib.h
char *numstr(unsigned int n, const int base)
{
static char buffer[65];
itoa(n, buffer, base);
return buffer;
}
Parmetros de tipo puntero[editar]
Anteriormente se mencion que en C++ los parmetros a una funcin pueden pasarse por
valor o por referencia, al respecto, podemos agregar que los parmetros tambin pueden
pasarse como punteros. El paso de parmetros de punteros es bastante parecido al paso de
parmetros por referencia, salvo que el proceso de los datos dentro de la funcin es diferente.
Por ejemplo, las funciones:
void referencia( int &X ) { X = 100; }
void puntero( int *X ) { *X = 100; }
ambas reciben un puntero o referencia a un objeto de tipo entero, por lo tanto cualquiera de
las funciones del ejemplo puede cambiar el valor de la variable entera apuntada por X, la
diferencia radica en la forma en que cada una de las mismas lleva cabo la tarea. Si en la
funcin puntero() en lugar de usar *X = 100; se usara X = 100; se le asignara 100 al puntero
X, ms no al objeto apuntado por X, y esto podra ser la causa de que el programa se
terminara de manera abrupta.
Parmetros estructurados[editar]
Al igual que cualquier otro tipo los parmetros de tipo estruturado pueden pasarse por valor o
por referencia, sin embargo, podra ser que si una estructura es pasada por valor el
compilador mostrara una advertencia ( warning ) indicando que se pasado por valor una
estructura, puesto que el paso de estructuras por valor es permitido usted puede ignorar la
advertencia, pero lo mejor es pasar estructuras por referencia. Si una estructura es pasada por
valor y si esta es muy grande podria ser que se agotara la memoria en el segmento de pila (
Stack Segment ), aparte de que la llamada a la funcin sera ms lenta.
Para ver un ejemplo, consideremos el caso del siguiente tipo estructurado:
struct empleado {
char nombre[32];
int edad;
char sexo;
};
Ahora, pensemos que deseamos escribir una funcin para imprimir variables del
tipo empleado. As, la funcin puede escribirse de las tres maneras siguientes:
void ImprimeEmpleadoV( empleado e)
{
cout << "Nombre: " << e.nombre << endl;
cout << "Edad: " << e.edad << endl;
cout << "Sexo: " << e.sexo << endl;

}

// Parametro empleado pasado por referencia
void ImprimeEmpleadoR( empleado &e )
{
cout << "Nombre: " << e.nombre << endl;
cout << "Edad: " << e.edad << endl;
cout << "Sexo: " << e.sexo << endl;

}

// Parametro empleado pasado como puntero
void ImprimeEmpleadoP( empleado *e )
{
cout << "Nombre: " << e->nombre << endl;
cout << "Edad: " << e->edad << endl;
cout << "Sexo: " << e->sexo << endl;
}
Funciones sobrecargadas[editar]
C++, a diferencia del C estndar, permite declarar funciones con el mismo nombre y a esto se
conoce como sobrecarga de funciones. Las funciones sobrecargadas pueden coincidir en
tipo, pero al menos uno de sus parmetros tiene que ser diferente. En todo caso, si usted trata
de declarar funciones sobrecargadas que coincidan en tipo y nmero de parmetros el
compilador no se lo permitir. Para poner un ejemplo vamos a considerar el caso de dos
funciones cuyo nombre ser divide, ambas regresarn el cociente de dos nmeros, salvo que
una de ellas operar sobre nmeros enteros y la otra lo har sobre nmeros reales ( de punto
flotante ).
Nota: cuando en los programas se hace una llamada a una funcin sobrecargada, el
compilador determina a cual de las funciones invocar en base al tipo y nmero de parmetros
pasados a la funcin.
#include <iostream.h>
#include <stdlib.h>

using namespace std;

// divide enteros
int divide(int a, int b)
{
cout << "divisin entera" << endl;
return ( (b != 0) ? a/b : 0);
}

// divide reales
double divide(double a, double b)
{
cout << "divisin real" << endl;
return ( (b != 0) ? a/b : 0);
}
// punto de prueba
int main()
{
cout << divide(10, 3) << endl;
cout << divide(10.0, 3.0) << endl;
cin.get();
}
Nmero variable de parmetros[editar]
En C,C++ se pueden crear funciones que operen sobre una lista variable de parmetros, es
decir, en donde el nmero de parmetros es indeterminado. En esta seccin se mostrar un
ejemplo de la manera en que podemos crear funciones para manejar tales asuntos, y para ello
haremos uso de tres macros soportadas por C++:
1. va_list puntero de argumentos
2. va_start inicializar puntero de argumentos
3. va_end liberar puntero de argumentos
La sintaxis que usaremos para declarar funciones con lista de parmetros variables es:
1) tipo nombrefuncion(...)
2) tipo nombrefuncion(int num, ...)
donde:
1. tipo es el tipo regresado por la funcin
2. nombrefuncion es el nombre de la funcin
3. int num es el nmero de parmetros que la funcin procesar
4. ... esta notacin se emplea para indicar que el nmero de parmetros es variable
Nota: observe que la primera forma de declaracin es realmente variable el nmero de
parmetros a procesar y en estos casos se debe establecer el mecanismo para determinar
cuando se ha procesado el ltimo de los argumentos, en el segundo tipo de declaracin el
nmero total de parmetros a procesar es igual al valor del parmetro num.
En el siguiente programa, por ejemplo, se define una funcin ( printstr ) que despliega una lista
variable de cadenas de caracteres.
#include <iostream.h>
#include <stdarg.h>

// despliega una lista de cadenas, la ultima debe ser NULL
void printstr(...)
{
va_list ap;
char *arg;
va_start(ap, 0);
while ( (arg = va_arg(ap, char*) ) != NULL) {
cout << arg;
}
va_end(ap);
}

int main()
{
printstr("Hola, ", "Esta es\n", "una prueba\n", NULL);
cin.get();
return 0;
}
En el programa que se listar en seguida, se define la funcin suma(), misma que operar
sobre listas de nmeros enteros, la funcin devolver la suma de dichos nmeros.
#include <iostream>//entrada y salida
#include <stdarg.h>

using namespace std;

// Esta funcin opera sobre una lista variable de nmeros enteros
int suma( int num, ... )
{
int total = 0;
va_list argptr;
va_start( argptr, num );

while( num > 0 ) {
total += va_arg( argptr, int );
num--;
}

va_end( argptr );
return( total );
}

int main()
{
cout << suma(4, 100, 200, 300, 400) << endl;
cin.get();
return 0;
}
Streams
Programacin en C++/Streams
Funciones Arrays y cadenas de texto
Contenidos
[ocultar]
1 Streams, entrada y salida de datos
o 1.1 La iostream
o 1.2 Streams automticos
o 1.3 Operadores de direccionamiento
o 1.4 Banderas de I/O
1.4.1 Banderas de formato:
1.4.2 Manipuladores
2 Streams para archivos o ficheros
o 2.1 Abrir y cerrar archivo
Streams, entrada y salida de datos[editar]
En este captulo abordaremos el tema de la manipulacin de datos a travs de los dispositivos
de entrada y salida estndar por medio de ciertos componentes lgicos conocidos
como: streams. A manera de definicin, un stream es una especie de canal a travs del cual
fluyen los datos. Tcnicamente, un stream es el enlace lgico utilizado por el programador en
C, C++ para leer o escribir datos desde y hacia los dispositivos estndar conectados a la PC.
Normalmente, el dispositivo estndar para manipular entradas es el teclado y este, en C++,
est asociado al objeto cin; el dispositivo estndar de salida est asociado (generalmente) con
la pantalla o monitor de despliegue de la PC y, el mismo, en C++ se puede acceder por medio
del objeto cout. El dispositivo estndar para mensajes de error es el cerr, y el mismo est
asociado por defecto con la pantalla o monitor de despliegue. Otro dispositivo estndar es la
impresora, pero este ltimo no es soportado por los objetos de la iostream. Los
programadores que hayan tenido alguna experiencia al programar en C estndar, notarn que
los tres objetos mencionados coinciden con los dispositivos: stdin, stdout y stderr. La tabla
que se muestra en seguida puede servirnos de base.

Tabla I/O : 01, dispositivos estndar de I/O
C estandar C++
stdin cin
stdout cout
stderr cerr
--- clog
La iostream[editar]
La iostream es la biblioteca estndar en C++ para poder tener acceso a los dispositivos
estndar de entrada y/o salida. En sus programas, si usted desea hacer uso de los
objetos cin, cout, cerr y clog tendr que incluir ( por medio de la directiva #include ) el uso
de la biblioteca iostream. En la iostream se encuentran definidas las clases ios ( misma que
es la base para las clases que implementen operaciones de entrada y/o salida de datos
), istream ( para operaciones de entrada ) y ostream ( para operaciones de salida ). Aparte de
las clases mencionadas, en la iostream se encuentra una lista de variables y constantes (
atributos ) que son accesibles por el usuario a travs del operador de mbito ( :: ).
Streams automticos[editar]
Si usted usa la directiva #include <iostream.h> o #include <iostream> en sus programas,
automticamente la iostream pone a su disposicin los objetos cin,cout, clog y cerr en el
mbito estndar (std), de tal manera que usted puede comenzar a enviar o recibir informacin
a travs de los mismos sin siquiera preocuparse de su creacin. Asi, un sencillo ejemplo del
uso de los objetos mencionados se muestra en seguida.
// De nuevo con el hola mundo...
#include <iostream.h>
int main()
{
std::cout << "Hola mundo"; // imprimir mensaje (en la pantalla)
std::cin.get(); // lectura ( entrada del teclado )
return 0;
}
Operadores de direccionamiento[editar]
Los operadores de direccionamiento son los encargados de manipular el flujo de datos desde
o hacia el dispositivo referenciado por un stream especfico. El operador de direccionamiento
para salidas es una pareja de smbolos de "menor que" <<, y el operador de direccionamiento
para entradas es una pareja de smbolos de "mayor que" >>. Los operadores de
direccionamiento se colocan entre dos operandos, el primero es el Stream y el segundo es
una variable o constante que proporciona o recibe los datos de la operacin. Por ejemplo, en
el siguiente programa y en la instruccin cout << "Entre su nombre: "; la constante "Entre su
nombre: " es la fuente o quien proporciona los datos para el objeto cout. Mientras que en la
instruccin cin >> nombre la variable nombre es el destino o quien recibe los datos
provenientes del objeto cin.
// De nuevo con el hola mundo...
#include <iostream.h>
int main()
{
char nombre[80];
cout << "Entre su nombre: ";
cin >> nombre;
cout << "Hola," << nombre;
cin.get();
return 0;
}
Observe que si en una misma lnea de comando se desea leer o escribir sobre varios campos
a la vez, no es necesario nombrar ms de una vez al stream. Ejemplos:
cout << "Hola," << nombre;
cin >> A >> B >> C;
Banderas de I/O[editar]
En esta seccin abordaremos de manera ms directa el tema sobre el control de formato para
los stream de C++. Especficamente, veremos las tres diferentes formas que existen en C++
para manipular las banderas relacionadas a los stream y que nos permitirn gobernar de una
manera ms precisa la forma para representar datos de salida. En ese sentido, veremos que
la primera de las forma que nos permitir el formateo sera a travs de las
funciones flags(), setf() yunsetf(), la segunda y la tercera forma las encontraremos en ciertos
manipuladores directos definidos en las bibliotecas <iostream> y <iomanip>.
Banderas de formato:[editar]
C++ define algunas banderas de formato para entradas y salidas estndar, las cuales pueden
ser manipuladas a travs de la funciones (mtodos) flags(), setf(), yunsetf(). Por ejemplo,
cout.setf(ios::left);
activa la justificacin a la izquierda para todas las salidas dirigidas hacia cout.

A continuacin se muestra una tabla de referencia de las banderas de I/O.
Tabla I/O : 02, banderas de formato
Bandera Descripcin
boolalpha Los valores booleanos pueden ser ledos/escritos usando las palabras "true" y "false"
dec Los valores numricos se muestran en formato decimal
fixed Nmeros de punto flotante se despliegan en forma normal
hex Los valores numricos se muestran en formato hexadecimal
left La salida es justificada por la izquierda
oct Los valores numricos se muestran en formato octal
right La salida es justificada por la derecha
scientific Nmeros de punto flotante se despliegan en notacin cientfica
showbase Despliega la base de todos los valores numricos
showpoint
Despliega el punto decimal y extra ceros, an cuando no sean
necesarios
showpos Despliega el smbolo de ms antes de valores positivos
skipws
Descarta caracteres de espaciado (espacios, tabuladores, nuevas lneas) cuando se lee desde
un stream
unitbuf Descarga el buffer despus de cualquier insercin
uppercase
Despliega la "e" en notaciones cientficas y la "x" en notaciones decimales como letras
maysculas

Manipulando la lista de banderas de I/O de C++ (mostrada arriba) se pueden controlar los
aspectos relacionados a la forma con la cual se desean presentar los datos en la salida. Por
ejemplo, el programa que se muestra en seguida, activa la bandera boolalpha para mostrar
los resultados de operaciones booleanas como "true" o "false" en lugar de "0" o "1" como es lo
normal.
// Programacin con C++
// programa Banderas01.cpp;
// probado en Dev-Cpp Versin 4.9.9.2

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
cout <<"\n0 > 1 ? "<<"\t"<<(0>1)<< endl;
cout <<"\t5 > 1 ? "<<"\t"<<(5>1)<< endl;

cout.setf(ios::boolalpha); // activar bandera
cout <<"\n0 > 1 ? "<<"\t"<<(0>1)<< endl;
cout <<"\t5 > 1 ? "<<"\t"<<(5>1)<< endl;

cin.get();
return 0;
}
Manipuladores[editar]
Las banderas tambin pueden manipularse directamente usando los siguientes
manipuladores. Seguramente usted ya estar familiarizado con el manipulador endl, el mismo
puede darle una idea de cmo son usados los manipuladores. Por ejemplo, usted puede
establecer la bandera de nmeros decimales usando el comando:
cout << dec;
La tabla que se muestra en seguida corresponde a los manipuladores definidos en
<iostream>.

Tabla I/O : 03, manipuladores en <iostream>
Manipulador Descripcin Entrada Salida
bollalpha Activa la bandera boolalpha X X
dec Activa la bandera dec-imal X X
endl Escribe carcter de cambio de lnea --- X
ends Escribe el carcter null --- X
fixed Activa la bandera fixed (para nmeros reales) --- X
flush Descargar el stream --- X
hex Activa la bandera hex-adecimal X X
internal Activa la bandera interna --- X
left Activa la bandera left (izquierda) --- X
nobollalpha Desactiva la bandera boolalpha X X
noshowbase Desactiva la bandera showbase --- X
noshowpoint Desactiva la bandera showpoint --- X
noshowpos Desactiva la bandera showpos --- X
noskipws Desactiva la bandera skipws X ---
nounitbuf Desactiva la bandera unitbuf --- X
nouppercase Desactiva la bandera uppercase --- X
oct Activa la bandera oct-al X X
right Activa la bandera de justificar derecha --- X
scientific Activa la bandera scientific --- X
showbase Activa la bandera showbase --- X
showpoint Activa la bandera showpoint --- X
showpos Activa la bandera showpos --- X
skipws Activa la bandera skipws X ---
unitbuf Activa la bandera unitbuf --- X
uppercase Activa la bandera uppercase --- X
ws Limpiar cualquier espacio al inicio X ---

El programa que se muestra en seguida es un ejemplo de como emplear manipuladores
directos para formatear salidas al stream estndar de salida ( cout ). En el mismo, se emplea
el manipulador boolalpha para que los resultados de la operaciones logicas sean textuales, o
sea, true o false y los manipuladores dec, hex yoct.
// Programacin con C++
// programa Banderas02.cpp;
// probado en Dev-Cpp Versin 4.9.9.2

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
cout << boolalpha;
cout << "0 > 1 ? " << '\t' << (0 > 1) << endl;
cout << "5 > 1 ? " << '\t' << (5 > 1) << endl;

cout << dec << 2048 << endl;
cout << hex << 2048 << endl;
cout << oct << 2048 << dec << endl;

cin.get();
return 0;
}

Por ltimo, y para terminar esta seccin, hablaremos de los manipuladores definidos en la
biblioteca <iomanip>. Estos operan directamente igual que los que se viern anteriormente,
salvo que son parametrizados, es decir, operan en lnea de salida mediante el operador <<,
pero los mismos operan a manera de funciones, o sea con parmetros.

Tabla I/O : 04, manipuladores en <iomanip>
Manipulador Descripcin Entrada Salida
resetioflags( long f ) Desactiva las banderas especificadas por f X X
setbase( int base ) Establece la bases numrica a base --- X
setfill( int ch ) Establece carcter de relleno a ch --- X
setioflags( long f ) Activa las banderas especificadas por f X X
setprecision( int p ) Establece el nmero de digitos de precisin a p --- X
setw( int w ) Establece la longitud de campo a w --- X

Atendiendo a las tablas de banderas, as como a las tablas de manipuladores para las mismas
mostradas arriba, usted puede (con practica y perceverancia) lograr salidas con muy buena
presentacin hacia los dispositivos estndar. Por ejemplo, el programa que se mostrar a
continuacin muestra una de las formas de emplear manipuladores para formatear nmeros
de punto flotante, en el programa se despliega una lista de valores numricos y se establece
el campo de salida a una longitud de 12 caracteres y dos decimales.
// Programacin con C++
// programa Banderas03.cpp;
// probado en Dev-Cpp Versin 4.9.9.2

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
double data[] = { 347.25, 45.75, 124.50, 456.80, 1500.90 };
double total;
int ancho = 12;

cout.precision(2);
cout.setf(ios::fixed);

for (int c = 0; c < 5; c++) {
cout << setw(ancho) << data[c] << endl;
total += data[c];
}
cout.fill('-');
cout << setw(ancho) << "" << endl;
cout.fill(' ');
cout << setw(ancho) << total << endl;

cout << "Por favor oprime Enter...";
cin.get();
return 0;
}
Streams para archivos o ficheros[editar]
Por definicin, un archivo es una coleccin de datos almacenados en algn lugar. En C++, el
programador puede considerar que un archivo es un stream, de tal manera que los objetos
vistos en la seccin anterior ( cin, cout, cerr y clog ) son una especie de archivo manipulados
por streams. Este punto es de suma importancia, ya que todo lo que se ha mencionado acerca
de los atributos, banderas y manipuladores; que son miembros de los objetos ( stream ) para
entrada y salida estndar, son aplicables a los streams que usemos para trabajar con archivos
en disco y/o cualquier otro dispositivo de almacenamiento. Hasta este momento, solamente se
ha mencionado que los streams poseen banderas y que las mismas pueden alterarse a traves
de los manipuladores, sin embargo, hace falta hablar acerca de los mtodos o funciones que
son miembros de dichos streams. As, antes de ver un ejemplo para mostrar el uso de
archivos en disco listaremos una tabla ms, o sea, la de los mtodos aplicables a los streams.

Tabla I/O : 05, mtodos para objetos istream, ostream y fstream
Funcin Descripcin
bad true si ha ocurrido un error
clear limpia las banderas de estado (status flags)
close cierra un stream
eof true si se alcanz el fin de archivo
fail true si ha ocurrido un error
fill establecer manipulador de carcter de relleno
flags accesa o manipula las banderas de formato de un stream
flush vaciar el buffer de un stream
gcount nmero de caracteres leidos durante la ltima operacin de entrada
get lectura de caracteres
getline lectura de una lnea de caracteres
good true si no ha ocurrido un error
ignore leer y descartar caracteres
open abrir un stream de entrada y/o salida
peek verifica la siguiente entrada de carcter
precision manipula la precisin del stream
put escritura de caracteres
putback regresar caracteres al stream
rdstate regresa la bandera de estado de stream
read lee datos de un stream hacia un buffer
seekg realiza acceso aleatorio sobre un stream de entrada
seekp realiza acceso aleatorio sobre un stream de salida
setf cambiar las banderas de formato
tellg lee el puntero del stream de entrada
tellp lee el puntero del stream de salida
unsetf limpiar las banderas de formato
width accesa y manipula la longitud minima del campo
write escritura datos desde un buffer hacia un stream
Abrir y cerrar archivo[editar]
A diferencia de los streams para dispositivos estndar, los cuales son creados y abiertos de
manera automtica, para trabajar con archivos en discos se debe primeramente "abrir el
archivo", y luego de haber terminado de leer o escribir datos en el mismo, se debe "cerrar el
archivo". En C++, en orden de trabajar con archivos en disco, podemos emplear las
clases fstream, ifstream, y ofstream. Si usted desea abrir un archivo especfico en modo de
lectura y escritura use un objeto de la clase fstream, por el contrario, si desea abrir un archivo
solo para lectura o solo para escritura use objetos de la clase ifstream y ofstream,
respectivamente.
La sintaxis para crear objetos de las tres clase mencionadas es:
'''streams para lectura y escritura'''
fstream();
fstream(const char*, int, int = filebuf::openprot);
fstream(int);
fstream(int _f, char*, int);

'''streams solo para lectura'''
ifstream();
ifstream(const char*, int, int = filebuf::openprot);
ifstream(int);
ifstream(int _f, char*, int);


'''streams solo para escritura'''
ofstream();
ofstream(const char*, int, int = filebuf::openprot);
ofstream(int);
ofstream(int _f, char*, int);
Observe que la sintaxis para crear objetos de las tres clases mostradas arriba es la misma. Es
decir,
1. El primer mtodo constructor crea un objeto que no est (an) asociado a un archivo
en disco, en estos casos, se tendr que usar el mtodostream.open("nombre de
archivo"); para establecer la conexin entre el stream y el archivo en disco.
2. El segundo mtodo constructor crea un objeto asociado a un archivo en disco, en
estos casos, el archivo en el disco queda abierto y asociado al stream. En este, el
parmetro char * apunta a una cadena de caracteres con el nombre del archivo.
3. El tecer mtodo crea un stream a raiz de un identificador de archivo.
4. El cuarto mtodo crea un stream a raiz de un identificador de archivo, un buffer y
tamao de buffer especficos.
Para nuestro primer ejemplo usaremos el segundo de los constructores mencionados. As, el
programa que se muestra en seguida realiza las siguientes tareas:
1. Crea y escribe sobre el archivo de texto test.$$$
2. Abre y lee los datos del archivo test.$$
3. Cierra el archivo test.$$
Para el caso que se presenta se debe prestar atencin a los metodos:
1. bad(), para verificar el estado de error del stream
2. get(), para leer caracteres del stream
3. put(), para escribir caracteres en el stream
4. close(), para cerrar el archivo.
// Ejemplo de ifstream y ofstream
// En este programa se demuestra la forma de crear un archivo
// en disco por medio de objeto ofstream, y la manera abrir y
// leer un archivo por medio de un objeto ifstream.

#include <iostream>
#include <fstream>
#include <string.h>


using namespace std;

char *filename = "test.$$$";
char *data = "Esta lnea de texto se guardar en el archivo test.$$$";

// crear un archivo en disco cuyo nombre es dado por filename
int crearArchivo(char *filename)
{
ofstream fichero(filename); // crear o rescribir archivo
// verificar la creacin del archivo
if ( fichero.bad() ) {
cout << "Error al tratar de abrir archivo";
cin.get();
return 1;
}

// escribir datos al archivo
for (unsigned int t = 0; t < strlen(data); t++ )
fichero.put(data[t] );

fichero.close();
cout << "archivo creado exitosamente" << endl;
return 0;
}

// abrir un archivo en disco cuyo nombre es dado por filename
int leerArchivo(char *filename)
{
ifstream fichero(filename); // abrir archivo para lectura

// verificar la apertura del archivo
if ( fichero.bad() ) {
cout << "Error al tratar de abrir archivo";
cin.get();
return 1;
}

// lectura de datos
while ( ! fichero.eof() ) cout << (char)fichero.get();
fichero.close();
cout << endl << "archivo leido exitosamente" << endl;
return 0;
}

int main()
{
crearArchivo(filename);
leerArchivo(filename);
cout << endl << "Presione <Enter>...";
cin.get();
return 0;
}

Usando operadores de redireccin ( <<, >> )
sobre streams asociados con archivos en disco.

No hay que olvidar que si un archivo es asociado a un stream las operaciones de entrada y/o
salida para dicho archivo se hacen a travez del stream y, por lo tanto, se puede usar, no solo
los operadores de redireccin, sino tambin todos los metodos, manipuladores y atributos que
se ha mencionado hasta este momento. As, el objetivo del siguiente programa es demostrar
como hacer uso del operador << sobre un archivo asociado a un stream de salida, y del
operador >> sobre un archivo asociado a un stream de entrada. El ejemplo que se mostrar
no es realmente til, sin embargo cumple con su cometido, es decir, el punto de interes del
mismo est en las lneas de cdigo:
while ( ! fin.eof() ) {
fin >> temp;
fout << temp ;
}
Encargadas de leer datos del archivo de entrada y de escribir los mismos en el archivo de
salida.

#include <iostream.h>
#include <fstream.h>

char *filename = "test.$$$";

// abre y lee datos de un archivo en disco cuyo nombre es dado por
filename
int leerArchivo(char *filename)
{
ifstream fichero(filename); // abrir archivo para lectura

// verificar la apertura del archivo
if ( fichero.bad() ) {
cout << "Error al tratar de abrir archivo";
cin.get();
return 1;
}

// lectura de datos
while ( ! fichero.eof() ) cout << (char)fichero.get();
fichero.close();
cout << endl << "archivo leido exitosamente" << endl;
return 0;
}

// crea una copia del archivo test.$$$ hacia test.bak
// Nota: ningn carcter de espaciado en el origen le es tranferido al
destino
int backup(char *filename)
{
char newname[80];
int i = 0;

// copia el nombre del archivo original y remplaza la extensin
por "BAK".
while (filename[i] != '.' ) newname[i] = filename[i++];
newname[i] = '\0';
strcat(newname, ".BAK");

ifstream fin( filename ); // abrir archivo de entrada
ofstream fout( newname, ios::trunc ); // abrir archivo de salida

char temp;
while ( ! fin.eof() ) {
fin >> temp;
fout << temp ;
}

fin.close();
fout.close();
return 0;
}

int main()
{
backup(filename);
leerArchivo("test.bak");
cout << endl << "Presione <Enter>...";
cin.get();
return 0;
}

Streams Desarrollo Orientado a Objetos
Contenido
[ocultar]
1 Arrays y cadenas de texto
2 Indices de un array
3 Dimensiones de un array
o 3.1 Array unidimensional
o 3.2 Array bidimensional
4 Declaracin de arrays en C, C++
o 4.1 Iteraciones dentro de un array (vector)
o 4.2 Iteraciones dentro de un array (matriz)
5 Cadenas de caracteres
o 5.1 La biblioteca string
6 Cadenas en C++
7 Arrays en C++
Arrays y cadenas de texto[editar]
Los arrays son usados extensamente por los programadores para contener listas de datos en
la memoria, por ejemplo, los datos almacenados en un disco suelen leerse y ponerse dentro
de un array con el objetivo de facilitar la manipulacin de dichos datos, ya que los datos en
memoria pueden ser modificados, clasificados, marcados para su eliminacion, etc. para luego
ser reescritos al disco. Otro ejemplo podra ser el de un men de opciones que se desplegarn
dentro de una ventana para que el usuario pueda elegir una de stas, en tales casos y cuando
las opciones son numerosas, solamente se ponen unas cuantas de ellas dentro de la ventana
pero se le da al usuario la oportunidad de poder subir y bajar a su antojo para ver el resto de
opciones que, aunque no se vean en la ventana, forman parte del men o array de opciones.
Array:
Un array es un conjunto de datos del mismo tipo ordenados en forman lneal uno despus de
otro. Los componentes de un array se han de referenciar por medio del nombre del array y un
ndice de desplazamiento para indicar el componente deseado.
Indices de un array[editar]
Los ndices son nmeros que se utilizan para identificar a cada uno de los componentes de un
array. A modo de ejemplo, podemos pensar que los ndices son como los nmeros de
habitaciones de un hotel, es decir, para poder dirigirnos a un hotel especfico es necesario
saber el nombre del mismo, luego, si queremos llegar a una habitacin especfica de dicho
hotel necesitaremos, adems del nombre del hotel, el nmero de habitacin deseado.
Dimensiones de un array[editar]
De acuerdo a la forma en que se construye o declara un array, ste puede ser clasificado
como: unidimensional, bidimensional y multidimensional. Los arrays que se emplean con
mucha ms frecuencia son los estructurados a manera de vector ( array unidimensional ) y los
estructurados a manera de matriz ( array bidimensional ), as, aunque en C++ se pueden crear
estructuras multidimensionales, en este captulo solo trataremos con vectores y matrices.
Array unidimensional[editar]

Una array uni-dimensional es aquel en donde los componentes son accesibles por medio de
uno y solamente un ndice que apunte al componente requerido. Los arrays de este tipo son
conocidos tambin con el nombre devectores. Conceptualmente, podemos pensar en un array
unidimensional como una lista compuesta de datos, donde para referirnos a uno de ellos
emplearemos un nmero para indicar la posicin del mismo dentro de la lista. Por ejemplo,
consideremos el caso de la tabla o array VentaSemanal, la cual est pensada para registrar
las ventas de cada uno de los das de la semana. De manera conceptual podemos ver el array
como se muestra a continuacin:
Nota: en C++ los arrays estn basados en 0 ( cero ), es decir, el primer elemento de un array
se indexa mediante el 0, y el ndice para el ltimo de los elementos es igual al nmero de
componentes menos uno.
array: VentaSemanal

+------+
| dato | <-- componente 0, ( fila 0 )
|------|
| dato | <-- componente 1, ( fila 1 )
|------|
| dato | ...
|------|
| dato | ...
|------|
| dato | ...
|------|
| dato | ...
|------|
| dato | <-- componente 6, ( fila 6 )
|------|
Si en el array VentaSemanal queremos que el elemento 4 ( por ejemplo ) contenga el valor de
8987 lo podemos lograr con la instruccin:VentaSemanal[4] = 8987; y el estado del array
sera:
array: VentaSemanal

+------+
| dato |
|------|
| dato |
|------|
| dato |
|------|
| dato |
|------|
| 8987 | <--- componente 4
|------|
| dato |
|------|
| dato |
|------|
Array bidimensional[editar]

Un array bi-dimensional es aquel en donde los componentes son accesibles por medio de una
pareja de ndices que apunten a la fila y a la columna del componente requerido. Los arrays
de este tipo son conocidos tambin con el nombre de matrices. Conceptualmente, podemos
pensar en un array bidimensional como en una lista compuesta de filas y columnas, en donde
para referirnos a una de ellas emplearemos un nmero para indicar la posicin de fila y otro
nmero para indicar la posicin de la columna del componente deseado. Por ejemplo,
consideremos el caso de la tabla o array VentaSemanaQ, la cual est pensada para registrar
las ventas de cada uno de los das de la semana por cuatro semanas, o sea, una tabla de 7 x
4 elementos. De manera conceptual podemos ver el array como se muestra a continuacin:
array: VentaSemanaQ

C O L U M N A S

+--- componente ( 0, 0 )
|
+------+------+------+------+
| dato | dato | dato | dato |
|------|------|------|------|
F | dato | dato | dato | dato |
|------|------|------|------|
I | dato | dato | dato | dato |
|------|------|------|------|
L | dato | dato | dato | dato |
|------|------|------|------|
A | dato | dato | dato | dato |
|------|------|------|------|
S | dato | dato | dato | dato |
|------|------|------|------|
| dato | dato | dato | dato |
+------+------+------+------+
|
+---- componente ( 6, 3 )
Si en el array VentaSemanaQ queremos que el elemento de la fila 4, columna 3 ( por ejemplo
) contenga el valor de 5000 lo podemos lograr con la instruccin: VentaSemanaQ[4][3] =
5000;y el estado del array sera:
array: VentaSemanaQ

+--- componente ( 0, 0 )
|
+------+------+------+------+
| dato | dato | dato | dato |
|------|------|------|------|
| dato | dato | dato | dato |
|------|------|------|------|
| dato | dato | dato | dato |
|------|------|------|------|
| dato | dato | dato | dato |
|------|------|------|------|
| dato | dato | dato | 5000 | <-- componente ( 4, 3 )
|------|------|------|------|
| dato | dato | dato | dato |
|------|------|------|------|
| dato | dato | dato | dato |
+------+------+------+------+
|
+---- componente ( 6, 3 )
Declaracin de arrays en C, C++[editar]
En C, C++ para declarar un array se emplea la sintaxis:
tipo identificador [tamao] = { lista de inicializacin } ;
donde,
tipo se refiere al tipo de datos que contendr el array. El tipo puede ser cualquiera de los
tipos estndar (char, int, float, etc.) o un tipo definido por el usuario. Es ms, el tipo del
array puede ser de una estructura creada con: struct, union y class.
identificador se refiere al nombre que le daremos al array.
tamao es opcional e indica el nmero de elementos que contendr el array. Si un array
se declara sin tamao, el mismo no podr contener elemento alguno a menos que en la
declaracin se emplee una lista de inicializacin.
lista de inicializacin es opcional y se usa para establecer valores para cada uno de los
componentes del array. Si el array es declarado con un tamao especfico, el nmero de
valores inicializados no podr ser mayor a dicho tamao.
Ejemplos:
int intA[5];
long longA[5] = { 1, 2, 3, 4, 5 };
char charA[3] = { 'a', 'b', 'c' };
Iteraciones dentro de un array (vector)[editar]
El termino Iterar se refiere al hecho de acceder (con el fin de leer o escribir) sobre cada uno de
los componentes de un array. As, para poner un ejemplo reconsideremos el caso de la
tablaVentaSemanal (vista en una seccin anterior), y que dicho sea de paso es un array de 7
elementos de tipo double. Luego, vamos a mostrar como ejemplo un programa completo en el
cual se declara el array mencionado con valores inicializados, que sern mostrados en
pantalla y al final la suma de estos. Observe que la variable i usada para iterar dentro del array
va desde 0 hasta FILAS - 1 ( FILAS es el tamao del array ).
Nota: por motivos de simplificacin el programa est escrito al estilo de C estndar. Sin
embargo puede ser compilado y ejecutado en un compilador de C++.
#include <stdio.h>
#include <stdlib.h>

#define FILAS 7

int main()
{
float ventas[FILAS] = {
123.50, 234.60, 345.45, 321.40, 345.00, 456.65, 0.0 };

float total = 0;
int i;

puts("Ventas de la semana");
puts("-------------------");

for (i=0; i<FILAS; i++) {
total += ventas[i];
printf( "%8.2f\n", ventas[i] );
}

puts("--------");
printf("%8.2f\n", total );

system("pause");
return 0;
}

Esta es la salida del programa:
Ventas de la semana
-------------------
123.50
234.60
345.45
321.40
345.00
456.65
0.00
--------
1826.60
Iteraciones dentro de un array (matriz)[editar]
Con el fin de leer o escribir sobre cada uno de los componentes de una matriz se deben crear
dos ciclos de iteracin. As, para poner un ejemplo reconsideremos el caso de la
tablaVentaSemanaQ (vista en una seccin anterior), y que dicho sea de paso es un array de 4
x 4elementos de tipo double. Luego, vamos a mostrar como ejemplo un programa completo
en el cual se declara el array mencionado con valores inicializados, que sern mostrados en
pantalla y al final la suma de estos. Observe que en este caso se utilizan dos variables, una
para iterar sobre las filas y otra para iterar sobre las columnas de la matriz.
#include <stdio.h>
#include <stdlib.h>
#define FILAS 7
#define COLS 4

int main()
{
float VentaSemanaQ[FILAS][COLS] = {
123.50, 234.60, 345.45, 321.40,
345.00, 456.65, 123.50, 234.60,
345.45, 321.40, 345.00, 456.65,
123.50, 234.60, 345.45, 321.40,
345.00, 456.65, 123.50, 234.60,
345.45, 321.40, 345.00, 456.65,
0.0, 0.0, 0.0, 0.0 };

float totales[COLS] = { 0.0, 0.0, 0.0, 0.0 };
float grantotal = 0;

int f, c, t = 0 ; /* indices para filas, columnas y totales */

puts("Ventas de cuatro semanas");
puts("------------------------");

for (f=0; f<FILAS; f++) {
for (c=0; c<COLS; c++) {
totales[c] += VentaSemanaQ[f][c];
printf("%8.2f ", VentaSemanaQ[f][c] );
}
puts("");
}

puts("--------------------------------------");
for (t=0; t<COLS; t++) {
printf("%8.2f ", totales[t] );
grantotal += totales[t];
}

printf("\n\nGran total: %10.2f\n", grantotal);
system("pause");
return 0;
}


Salida del programa:

Ventas de cuatro semanas
------------------------
123.50 234.60 345.45 321.40
345.00 456.65 123.50 234.60
345.45 321.40 345.00 456.65
123.50 234.60 345.45 321.40
345.00 456.65 123.50 234.60
345.45 321.40 345.00 456.65
0.00 0.00 0.00 0.00
--------------------------------------
1627.90 2025.30 1627.90 2025.30

Gran total: 7306.40
Cadenas de caracteres[editar]
En C, C++ las cadenas de caracteres no son ms que arrays de caracteres, salvo que a este
tipo de arrays el compilador les da un tratamiento especial. Usted puede manipular las
cadenas de caracteres de la misma manera en que manipula cualquier otro tipo de array, sin
embargo, es preferible hacer uso de una librera estndar especialmente escrita para
manipulacion de cadenas de caracteres, me refiero a la librera <string.h> y que viene
incluida con todo compilador de C, C++.
Para comenzar y antes de ver algunas de las funciones de la mencionada librera, tenemos los
siguientes ejemplos:

1. char nombre[] = "Oscar";
2. char nombre2[] = { 'O', 's', 'c', 'a', 'r', '\0' };
En el ejemplo 1 se est declarando la variable nombre como una cadena de caracteres y
cuyo contenido inicial es "Oscar".
En el ejemplo 2 se est declarando la variable nombre2 como una cadena de caracteres
y cuyo contenido inicial es { 'O', 's', 'c', 'a', 'r', '\0' };.
En ambos casos el resultado es el mismo, es decir, al final se obtiene la misma cadena, pero
usted debe poner atencin al hecho de que toda cadena de caracteres en C, C++ debe
terminar con el carcter NULL, que normalmente es igual a cero y se puede escribir como '\0'.
Ahora bien, cuando usted usa la sintaxis mostrada en el ejemplo 1 no tiene que preocuparse
por agregar el caracter NULL, ya que esto lo hace el compilador automticamente.
La biblioteca string[editar]
Los compiladores de C, C++ dan soporte a la biblioteca de funciones <string.h>, a la que
accede por medio de la directiva #include <string.h>. No veremos en detalle todas las
funciones contenidas en dicha biblioteca, y nos limitaremos a mostrar algunos ejemplos de
ciertas funciones importantes.

strlen(): Obtener longitud de cadenas
Sintaxis: size_t strlen(const char *s);
Comentarios: La funcin strlen() devuelve la longitud de la cadena s.
Ejemplo:
char *nombre = "Oscar E. Palacios";
cout << strlen(nombre) << endl;
strcpy(): Copiar cadenas
Sintaxis: char *stpcpy(char *dest, const char *src);
Comentarios: stpcpy copia la cadena src hacia dest, la funcin termina hasta haber
encontrado en src el carcter de terminacin null.
Ejemplo:
char *nombre = "Oscar E. Palacios";
char copia[80];
strcpy(copia, nombre);
cout << copia << endl;
strcat(): Concatenar cadenas
Sintaxis: char *strcat(char *dest, const char *src);
Comentarios: strcat agrega la cadena src a dest, la funcin termina hasta haber
encontrado en src el carcter de terminacin null.
Ejemplo:
char nombre[] = "Oscar E.";
char copia[80] = " Palacios";
strcat(copia, nombre);
cout << copia << endl;
strlwr(): Convertir a minsculas.
Sintaxis: char *strlwr(char *dest);
Comentarios: strlwr convierte todos los caracteres alfabticos ( 'A' .. 'Z' ) en dest a sus
correspondientes caracteres alfabticos ( 'a' .. 'z' ).
Ejemplo:
char nombre[] = "Oscar E. Palacios";
strlwr(nombre);
cout << nombre << endl;
strupr(): Convertir a maysculas.
Sintaxis: char *strupr(char *dest);
Comentarios: strupr convierte todos los caracteres alfabticos ( 'a' .. 'z' ) en dest a sus
correspondientes caracteres alfabticos ( 'A' .. 'Z' ).

strchr(): Buscar carcter ( hacia adelante )
Sintaxis: char *strchr(char *s, int c);
Comentarios: strchr busca en s el caracter c. La busqueda se lleva a cabo desde el
inicio hasta el final de s.
Regreso: si la operacin es exitosa strchr regresa un puntero hacia la primera
ocurrencia de c en s, en caso contrario strchr regresa null.
Ejemplo:
char nombre[] = "Oscar E.
Palacios";
char *p;

p = strchr(nombre, 'E');
if (p) {
cout << "nombre
contiene a E" << endl;
cout << "indice = "
<< (p - nombre) << endl;
}
else cout << "E no est en
nombre" << endl;

strrchr(): Buscar carcter ( hacia atras
)
Sintaxis: char *strrchr(char *s, int c);
Comentarios: strchr busca en s el caracter c. La busqueda se lleva a cabo desde el
final hasta el inicio de s.
Regreso: si la operacin es exitosa strchr regresa un puntero hacia la ltima
ocurrencia de c en s, en caso contrario strchr regresa null.
Ejemplo:
char nombre[] =
"Oscar E. Palacios";
char *p;

p = strrchr(nombre,
'E');
if (p) {
cout <<
"nombre contiene a E"
<< endl;
cout <<
"indice = " << (p -
nombre) << endl;
}
else cout << "E no
est en nombre" <<
endl;

strstr(): Buscar subcadena
Sintaxis: char *strstr(const char *s1, char *s2);
Comentarios: strstr busca en s1 la subcadena s2. La bsqueda se lleva a cabo desde
el inicio hasta el final de s1.
Regreso: si la operacin es exitosa strstr regresa un puntero hacia la primera
ocurrencia de s2 en s1, en caso contrario strstr regresa null.
Ejemplo:
char s[] =
"Un barco de
tristeza";
char *p;

p =
strstr(s,
"barco");
if (p) {

cout <<
"barco est
en s" <<
endl;

cout <<
"indice = "
<< (p - s)
<< endl;
}
else cout <<
"barco no
est en s"
<< endl;
Cadenas
en
C++[editar]
En la seccin
anterior
descubrimos
algunas
funciones para
trabajar con
cadenas de
caracteres al
estilo de C
estndar, si bien
no est de ms
tener tal
conocimiento,
tambin es
cierto que C++
es un lenguaje
de
programacn
orientado a
objetos, de tal
manera que
ciertos
compiladores (
como el gcc,
utilzado
porBloodshed
Dev-C++ y otros
tantos entornos
de desarrolo )
dan soporte a la
clase cstring,
que no debe
confundirse con
la <string.h>.
Nota: Bloodshed Dev-C++ es un IDE(Editor con Depurador Integrado) para programar
en C++ en un ambiente grfico para Windows, distibuido gratuitamente bajo
licencia GPL GNU y usted puede encontrarlo aqu:www.bloodshed.net. Actualmente
(febrero de 2008) se recomienda bajar la versin Dev-C++ 4.9.9.2.
Nota:Como el Dev-c++ ya esta descontinuado, es recomendable usar su extensin
Wx Dev-C++ que esta actualmente activa y es recomendable para muchos proyectos
bajo el lenguaje C++, este programa tambien es licencia GPL, podras descargarlo
desde=wxdsgn.sourceforge.net, y encontraras informacion de este
aqui=es.wikipedia.org/wiki/WxDev-C%2B%2B.

Una de las ventajas que ofrece la clase cstringes que, a diferencia de las cadenas estndar,
sta posee la capacidad de crecer o disminuir su tamao en tiempo de ejecucin. Adems,
entre otras caracteristicas destacables, la clase string soporta operaciones de asignacin tales
como: =, +, +=, etc.; y de comparacin tales como: ==, <=, etc.
Para tener una idea bsica sobre las cadenas en C++ veamos el siguiente programa:
Nota: en el programa se debe de observar el uso del operador de asignacin +=, algo
que no es posible hacer con las cadenas estndar.
// Ejemplo: demostracin de la clase string
// Compilado y ejecutado con exito en Bloodshed Dev-C++
#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
string s("Hola, ");
s += "cmo estan ustedes...";
cout << s << endl;
system("PAUSE");
return EXIT_SUCCESS;
}
Un estudio exhaustivo sobre la clase string requiere de un captulo completo, ya que la
misma, segn el manual de referencia de C++, posee aproximadamente 33 mtodos y
unos 7 constructores; adems de los atributos.
Arrays en C++[editar]
As como C++ da aternativas elegantes para la manipulacin de cadenas de caracteres,
tambin da el soporte para la manipulacon de arrays dinmicos. Este tema ser
ampliado en el captulo Libreria de Plantillas Estndar STL, sin embargo para tener una
idea de lo que vendr mostraremos aqu un ejemplo sencillo en donde se usar la clase
plantilla vector.
// Ejemplo: demostracin de la clase vector
// Compilado y ejecutado con exito en Bloodshed Dev-C++
#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
// creacin de un vector de enteros
vector<int> v;

// metiendo datos en el vector
for (int x = 500; x<1000; x+=50)
v.push_back(x);

// desplegando los datos del vector
for (int x = 0; x < v.size(); x++)
cout << "v[" << x << "] = " << v[x] << endl;

system("PAUSE");
return EXIT_SUCCESS;
}
Desarrollo Orientado a Objetos
Programacin en C++/Desarrollo Orientado a Objetos
Arrays y cadenas de texto Objetos y Clases
Desarrollo Orientado a Objetos[editar]
Antes de empezar a programar con objetos, es necesario entender ciertos conceptos bsicos.
Terminologa
El paradigma de Programacin Orientada a Objetos utiliza algunos trminos bsicos que se
explicarn a continuacin.
Objeto. Es una entidad que tiene atributos o propiedades y que presenta un
comportamiento. Puede ser un objeto del mundo real, o una abstraccin al mundo
informtico. Ejemplo, un automvil, una persona, un animal, etc.
Clase. Los humanos percibimos el mundo como un entorno compuesto de cosas, objetos,
les llamamos. Interactuamos con tantos, que lo natural es agruparlos de acuerdo a sus
caractersticas ms relevantes o generales. En otras palabras, los clasificamos en clases.
Todos los objetos que pertenecen a una clase, contiene todos los elementos comunes a
todos los objeto y no particulariza en los elementos que distinguen a los objetos entre s;
ejemplo, la clase automvil, comprende todos los automviles que circulan en este
momento por las calles. Incluira elementos que asociamos a los automviles, como
llantas, puertas, asientos, volante, etctera, pero no particularizara en cuestiones como
color, nmero de registro o caractersticas individuales a cada auto.
Propiedad. Una caracterstica asociada a una clase. Ejemplo, todos los autos tienen un
color, o un registro aunque esta propiedad vare entre objetos.
Mtodo. Posible accin que los objetos de una clase pueden realizar. En trminos
informticos, un algoritmo que pueden ejecutar. Ejemplo: todos los autos pueden acelerar,
frenar, etc.
Caractersticas de la programacin orientada a objetos[editar]
Encapsulamiento. Cuando conducimos un auto, no es necesario que nos enteremos de
como hace el motor para girar las ruedas del vehculo. Esos pormenores quedan ocultos
al usuario o encapsulados en la estructura del la clase auto. Cada objeto presenta una
interfaz al usuario de mtodos y propiedades con las cuales se interacta con l. As se
protege el objeto y todos los miembros de su clase, de alteraciones directas a sus
mtodos y propiedades.
Polimorfismo. Una vez que aprendemos a conducir un auto, podemos manejar
prcticamente cualquier auto. Esto se debe a que la interfaz que presentan los objetos
auto a los usuarios, es ms o menos la misma para cada auto. Todos tiene mtodos para
acelerar, y si bien, posiblemente los pormenores de como acelera cada auto, sean
sustancialmente diferentes; el usuario hace referencia a un mismo mtodo en todos los
autos. En trminos informticos, objetos de clases diferentes; incluso en la misma clase;
pueden tener mtodos homnimos, que hagan cosas equivalentes aunque los detalles del
como, sean diferentes.
Herencia. La clase auto es una clase muy general; se puede hacer un desglose ms
pormenorizado, por ejemplo, si hacemos subclases de autos deportivos, utilitarios,
compactos, manuales, automticos, de lujo, etc. Cada subclase toma de su clase base (o
superclase, en la jerga informtica) las propiedades y mtodos ms generales y agrega
las propias. As, como todos los autos, tienen color y registro, as que stas estaran
contenidas en la superclase auto. Propiedades como Capacidad en toneladas, sistema
estreo o cantidad de velocidades, estaran delegadas a las subclases ms particulares.
Objetos y Clases
Programacin en C++/Objetos y Clases
Desarrollo Orientado a Objetos Sobrecarga de Operadores
Contenido
[ocultar]
1 Clases y Objetos
2 Fundamentos de Clases
o 2.1 Resolucin de mbito
o 2.2 Acceso a las funciones
o 2.3 Ejemplo
3 Miembros de una clase ( mtodos y atributos )
4 Visibilidad de los miembros de una clase
5 Subclases
6 Herencia
o 6.1 Herencia por extensin
o 6.2 Agregacion o composicin
7 Constructores
8 Destructores
Clases y Objetos[editar]
Este capitulo introduce a las clases en C++. La clase es la fundacin de C++ para el soporte
de la programacin orientada a objetos, y se encuentra en el ncleo de muchas de sus ms
avanzadas caractersticas. La clase es la unidad bsica de C++ de la encapsulacin y esta
provee el mecanismo por el cual los objetos son creados.
Fundamentos de Clases[editar]
Vamos a comenzar definiendo los trminos de clase y objeto. Una clase define un nuevo tipo
de dato que especifica la forma de un objeto. Una clase incluye los datos y el cdigo que
operar sobre esos datos. Adems, una clase enlaza datos y cdigo. C++ usa una
especificacin de una clase para construir objetos. Los objetos son instancias de una clase.
Adems, una clase es esencialmente una serie de planes que especifican cmo construir un
objeto. Es importante tener claro esto: Una clase es una abstraccin lgica.
No es sino hasta que un objeto de esa clase sea creado que la representacin fsica de la
clase existe en la memoria. Cuando se define una clase, se declaran los datos que sta
contiene y el cdigo que opera en esos datos. Aunque clases muy simples pueden contener
slo cdigo o slo datos, la mayora de las clases contienen ambos. En conjunto, los datos se
almacenan en las variables y el cdigo en las funciones. Colectivamente, las funciones y
variables que constituyen una clase son llamados 'miembros' de la clase. Una variable
declarada dentro de una clase es llamada 'variable miembro', y una funcin declarada en una
clase es llamada 'funcin miembro'. En ocasiones el trmino 'variable de instancia' es usado
en lugar de variable miembro.
Una clase es creada con la palabra clave class. La declaracin de una clase es similar
sintcticamente a una estructura ( y tienen muchsimo que ver ). Aqu tenemos un ejemplo. La
siguente clase define un tipo llamadoCRender, el cual es usado para implementar
operaciones de renderizado en este caso.
// Esto define la clase CRender
class CRender {
char buffer[256];
public:
void m_Renderizar();
};

Veamos ms de cerca esta declaracin de la clase.
Todos los miembros de CRender son declarados dentro de la declaracin 'class'. La variables
miembro de CRender es buffer. La funcin miembro es m_Renderizar.
NOTA: Por defecto los miembros de una clase son privados.
Una clase puede contener tanto miembros privados como pblicos. Por defecto, todos los
elementos definidos en una clase son privados. Por ejemplo la variable buffer es privada. Esto
significa que slo pueden acceder a ella otros miembros de la clase CRender, cosa que no
podr hacer ninguna otra parte del programa. Es una forma de lograr la encapsulacin: se
puede controlar el acceso a ciertos elementos de datos mantenindolos privados. Aunque no
hay ninguna en este ejemplo, se pueden definir funciones privadas, las cuales pueden ser
llamadas solamente por otros miembros de la clase.
Para hacer pblica una parte de la clase ( accesible a otras partes del programa ), se debe
declarar con la palabra clave public. Todas las variables o funciones definidas despus de la
declaracin pblica son accesibles por todas las dems funciones en el programa. En nuestra
clase CRender, la funcin m_Renderizar() es pblica. Tpicamente, su programa acceder a
los miembros privados de una clase a travs de sus funciones pblicas. Note que la palabra
clave public es seguida con : . Mantenga en mente que un objeto forma una relacin entre
cdigo y datos. Una funcin miembro tiene acceso a los elementos privados de su clase. Esto
significa que m_Renderizar tiene acceso a buffer en nuestro ejemplo. Para aadir una funcin
miembro a la clase, debe especificar su prototipo en la definicin de la misma.
Una vez que se ha definido una clase, se puede crear un objeto de ese tipo usando el nombre
de la clase. El nombre de la clase se convierte en un especificador del nuevo tipo. Por ejemplo
la siguiente declaracin crea 2 objetos llamados render1 y render2 del tipo CRender.
CRender render1, render2;
Cuando un objeto de la clase es creado, ste tendr su propia copia de las variables
miembros que contiene la clase. Esto significa que render1 y render2 tendrn su propia e
independiente copia de buffer. Los datos asociados con render1 son distintos y separados de
los datos asociados con render2.
Recordemos: En C++, una clase es un nuevo tipo de dato que puede ser usado para crear
objetos. Especficamente, una clase crea una consistencia lgica que define una relacin entre
sus miembros. Cuando se declara una variable de una clase, se est creando un objeto. Un
objeto tiene existencia fsica, y es una instancia especfica de una clase. ( Esto es, un objeto
ocupa espacio de memoria, pero una definicin de tipo no ). Adems, cada objeto de una
clase tiene su propia copia de los datos definidos dentro de esa clase.
Dentro de la declaracin de CRender, el prototipo de una funcin es especificado. Ya que las
funciones miembros son prototipadas dentro de la definicin de la clase, no necesitan ser
prototipadas en otro lugar cualquiera.
Para implementar una funcin que es un miembro de una clase, debe indicarle al compilador a
cual clase pertenece la funcin calificando el nombre de la funcin con el nombre de la clase.
Por ejemplo, esta es una manera de codificar la funcin m_Renderizar().
void CRender::m_Renderizar()
{
strcpy(buffer, "C++ en wikibooks");
return;
}
Resolucin de mbito[editar]

El :: es llamado el operador de resolucin de mbito. Esencialmente le dice al compilador que
esta versin de m_Renderizar pertenece a la clase CRender. Dicho de otra forma, :: declara
que m_Renderizar se encuentra en el mbito de CRender. Varias clases diferentes pueden
usar los mismos nombres de funcin. El compilador sabe cul funcin pertenece a cul clase y
esto es posible por el operador de resolucin de mbito y el nombre de la clase.
Acceso a las funciones[editar]

Las funciones miembros de una clase slo pueden ser llamadas relativas a un objeto
especfico. Para llamar a una funcin miembro desde alguna parte del programa que se
encuentre fuera de la clase, se debe usar el nombre del objeto y el operador de
direcionamiento '.' ( punto ). Por ejemplo, lo siguiente llama a m_Renderizar() en el objeto
objeto1.
CRender objeto1, objeto2;

objeto1.m_Renderizar();
La invocacin de objeto1.m_Renderizar() causa a m_Renderizar() operar en los datos de la
copia de objeto1. Mantenga en mente que objeto1 y objeto2 son 2 objetos separados. Esto
significa, por ejemplo, que inicializar objeto1 no causa que objeto2 sea inicializado, La nica
relacin que objeto1 tiene con objeto2 es que es un objeto del mismo tipo.
Cuando una funcin miembro llama a otra funcin miembro de la misma clase, puede hacerlo
directamente, sin usar un objeto y el operador '.' En este caso, el compilador ya conoce en
cul objeto se est operando. Solamente cuando una funcin miembro es llamada por cdigo
que se encuentra fuera de la clase es cuando debe utilizarse el nombre del objeto y el
operador '.' Por la misma razn, una funcin miembro puede referirse directamente a una
variable miembro, pero cdigo fuera de la clase debe referenciarse a la variable a travs de un
objeto y el operador '.'
El programa siguiente muestra aqu todas las piezas juntas y detalles perdidos, e ilustra la
clase CRender.
Ejemplo[editar]
// Programa OPP01.CPP
#include <iostream>
#include <cstring>

using std::cout;
using std::endl;


// Esto define la clase CRender
class CRender {
public:
char buffer[256];
void m_Renderizar(const char *cadena);
};


/* implementar m_Renderizar() para la c;*/
void CRender::m_Renderizar(const char *cadena){
strcpy(buffer, cadena);//copia la cadena
return;
}


int main (int argc, char **argv){
// crear 2 objetos CRender
CRender render1, render2;

render1.m_Renderizar("Inicializando el objeto render1");
render2.m_Renderizar("Inicializando el objeto render2");

cout << "buffer en render1: ";
cout << render1.buffer << endl; // tenemos acceso a buffer ya
que es publico.

cout << "buffer en render2: ";
cout << render2.buffer << endl;

return (0);
}
Este programa imprime:
buffer en render1: Inicializando el objeto render1
buffer en render2: Inicializando el objeto render2
Miembros de una clase ( mtodos y atributos )[editar]
En el lenguaje coloquial de la programacin orientada al objeto es comn escuchar trminos
tales como: mtodos, atributos, herencia,polimorfismo, etc. En esta seccin nos
encargaremos de hablar de los dos primeros.
Mtodos:
En comparacin con la programacin tradicional, un mtodo es lo mismo que una
funcin cualquiera, salvo que como los mtodos se declaran para pertenecer a una
clase especfica, se dice que todos los mtodos de dicha clase son miembros de la
misma. Por lo dems, la declaracin y definicin de los mtodos es exactamente igual
que declarar y definir cualquier otra funcin.
Atributos:
En comparacin con la programacin tradicional, un atributo es lo mismo que una
variable cualquiera, salvo que como los atributos se declaran para pertenecer a una
clase especfica, se dice que todos los atributos de dicha clase son miembros de la
misma. Por lo dems, la declaracin de los atributos es exactamente igual que
declarar cualquier otra variable.

Miembros:
A partir de este momento usaremos la palabra miembro para referirnos al hecho de
que un mtodo o un atributo pertenece a tal o cual clase.
Por Ejemplo, en el programa OOP01.CPP ( visto anteriormente ) la
Clase CRender posee dos miembros, buffer que es un atributo; y m_Renderizar
que es un mtodo.
class CRender {
public:
char buffer[256]; // atributo
void m_Renderizar(const char *cadena); // mtodo
};
Visibilidad de los miembros de una clase[editar]
Por visibilidad se entiende al acto de acceder a los miembros de una clase. En
este sentido, los miembros de una clase pueden
ser: pblicos,privados y protegidos.
Un miembro pblico significa que el acceso al mismo puede darse dentro del
interior de la clase, dentro de una subclase, y desde un objeto instanciado de
cualquiera de estas. Por ejemplo, los miembros de la claseCRender son
accesibles dentro de la misma y podrn accederse desde cualquier otra clase
que se derive de CRender, as como desde cualquier objeto instanciado de
estas.
Un miembro privado significa que el acceso al mismo puede darse solamente
dentro del interior de la clase que lo posee. Normalmente, el programador
creador de una clase declara a los atributos de la clase como privados y a los
mtodos como pblicos, esto con la idea de que el usuario de la clase no
pueda tener acceso a los atributos sino es a traves de los mtodos definidos
para el caso.
Un miembro protegido se comporta de manera parecida a un miembro
privado, salvo que estos son accesibles dentro de la clase que lo posee y
desde las clases derivadas, pero no desde los objetos instanciados a raiz de
dichas clases.
Nota: por defecto, los miembros de una clase son privados.

En la clase Pareja que se ver en seguida, se declaran dos atributos y cuatro
mtodos para la manipulacin de dichos atributos. Observe que los atributos son
privados( por defecto ), mientras que los mtodos se declaran pblicos.
class Pareja
{
// atributos
double a, b;

public:
// mtodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};

// implementacin de los mtodos de la clase Pareja
//
double Pareja::getA() { return a; }
double Pareja::getB() { return b; }
void Pareja::setA(double n) { a = n; }
void Pareja::setB(double n) { b = n; }
Subclases[editar]
Una subclase es una clase que se deriva de otra. La clase que sirve de base
suele conocerse como parent (padre), y a la subclase se le llama child (hija). En
C++ cada clase que es creada se convierte en candidata para servir de base de
donde se deriven otras. Por ejemplo, la clase Pareja es candidata para
convertirse en la base para las subclases Suma, Resta,Multiplica, Divide, y
otras posibles subclases en donde se utilice un par de valores numricos.
Para poner un ejemplo, pensemos en que deseamos crear la clase Suma, misma
que ser utilizada para obtener la suma de dos nmeros. Puesto que la clase
Pareja posee dos atributos nmericos puede ser usada como base para la clase
que estamos proyectando. As, el siguiente ejemplo se constituye en un caso de
clases derivadas.
Nota: Observe que la sintaxis para crear una subclase es:
class hija : [public | private] padre // Qu significan
public y private aqu?
{
...
};

Donde padre es la clase base e hija es la subclase.
class Suma : public Pareja
{
// atributos de Suma
double resultado;

public:
// mtodos de Suma
double calcular();
};

// implementacin de Suma
//
double Suma::calcular() { return getA() + getB(); }

Probando las clases Pareja y Suma
// programa OOP02.CPP
// Este programa pone a prueba el uso de las clase Suma,
// misma que es una subclase de la clase Pareja ( ambas
definidas anteriormente).

#include <iostream.h>

int main()
{
Suma s;
s.setA(80);
s.setB(100);
cout << s.getA() << " + " << s.getB() << " = " <<
s.calcular() << endl;
cin.get();
return 0;
}
Herencia[editar]
La herencia es uno de los mecanismos ms tiles de la programacin orientada
al objeto, ya que por medio de la misma se puede llevar a cabo la reutilizacin de
cdigo. Es decir, puesto que toda clase definida se convierte en candidata para
ser usada como base de donde se deriven otras, esto da como resultado que las
clases derivadas hereden todos los miembros de la clase base. Por ejemplo, la
clase Sumavista en la seccin anterior, hereda todos los miembros de la
clase Pareja puesto que Suma es una extensin de Pareja. En ese sentido,
podemos decir que existen dos tipos de herencia, por extensin y
por agregacin ocomposicin. En el caso de las clases Pareja y Suma, se dice
que Suma es una extensin de Pareja. Vista grficamente, la herencia por
extensin se puede representar as:
Herencia por extensin[editar]

Herencia
Al tipo de diagrama mostrado arriba (Herencia por extensin) se le conoce
como UML [1] y es utilizado para mostrar de forma grafica la relacin existente
entre una clase hija con la clase padre. En el caso del ejemplo, se muestra que la
clase Suma es una extensin de la clase Pareja y, en consecuencia, Suma posee
a los miembros { a, b, getA(), getB(), setA(), setB() } heredados de la clase
Pareja. Observe como la clase Suma posee otros dos miembros no heredados,
{ resultado, y calcular() }, y es precisamente a este tipo de situacin por lo que
se dice que Suma es una extensin de Pareja, ya que Suma, adems de poseer a
todos los miembros de Pareja, se extiende para poseer otros dos miembros.
Agregacion o composicin[editar]
La composicin se da en los casos en donde una clase posee un objeto que es
una instancia de otra clase. Por ejemplo, la clase Suma podra escribirse de la
siguiente forma:
class Suma
{
// atributo privado
double resultado;

public:
// mtodo pblico
double calcular();

// atributo pblico
Pareja p;
};

// implementacin del metodo calcular de la clase Suma.
double Suma::calcular() { return p.getA() + p.getB(); }
Luego, si usted presta atencin, notar que el miembro p de la clase Suma es un
objeto o instancia de la clase Pareja, en consecuencia, la clase Suma puede
acceder a los miembros de la clase Pareja a travs de la variable p. Tambin se
debe observar que la implementacin del mtodo calcular() es diferente que el
mismo de la clase Suma original. Si usted desea poner a prueba a la nueva clase
Suma, compile y ejecute el siguiente programa.


// programa herencia_por_composicion.CPP

#include <iostream>
using namespace std;

class Pareja
{
// atributos
double a, b;

public:
// mtodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};

// implementacin de los mtodos de la clase Pareja
double Pareja::getA() { return a; }
double Pareja::getB() { return b; }
void Pareja::setA(double n) { a = n; }
void Pareja::setB(double n) { b = n; }

class Suma
{
// atributo privado
double resultado;

public:
// mtodo pblico
double calcular();
// atributo pblico
Pareja p;
};
// implementacin del metodo calcular de la clase Suma.
double Suma::calcular() { return p.getA() + p.getB(); }

int main()
{
Suma s;
s.p.setA(80);
s.p.setB(100);
cout << s.p.getA() << " + " << s.p.getB() << " = " <<
s.calcular() << endl;
cin.get();
return 0;
}
////SALIDA////
80 + 100 = 180
Constructores[editar]
Un constructor es un mtodo que pertenece a una clase y el cual (en C++) debe
tener el mismo nombre de la clase a la que pertenece. A diferencia de los otros
mtodos de la clase, un constructor deber ser del tipo void, es decir, el mismo
no regresar valor alguno. Una clase puede tener ms de un mtodo constructor.
Cada clase debe tener al menos un constructor, tanto as que si el programador
creador de una clase no define un mtodo constructor para la misma, el sistema,
o sea el compilador, crear de manera automtica un constructor nulo.
El objetivo principal del constructor es establecer las condiciones necesarias
dentro de la memoria y crear una copia del objeto mismo dentro de la memoria.
Los constructores suelen usarse para la inicializacin de los atributos de los
objetos instanciados. Por ejemplo, con las instrucciones:
Suma s;
s.setA(80);
s.setB(100);
del programa OOP02.CPP, se declara el objetos de la clase Suma y luego se
inicializan los atributos del objeto por medio de los mtodos setA() y setB(). En
este caso, es necesario hacer uso de dichos mtodos debido al hecho de que no
se ha definido un constructor para la clase Suma. Ahora bien, para evitar este tipo
de situaciones podemos definir un mtodo constructor para Suma y que este se
encargue de inicializar los atributos. Veamos.
Notas: ya que Suma es una extensin de Pareja, se ha definido el mtodo
constructor de Pareja y ste a la vez es invocado por el constructor de Suma. Otro
punto de inters es el hecho de la definicin de un constructor base para Pareja,
ya que de acuerdo con las reglas de programacin en C++ toda clase en donde
se defina un constructor parametrizado deber definir un constructor base; esta
regla se aplica en los casos en donde la clase proyectada servir de base para
otras.
// programa OOP04.CPP
// Ejemplo: clases Pareja y Suma, ambas con constructor

#include <iostream>
using namespace std;

//------------------------
class Pareja
{
// atributos
double a, b;

public:
// constructor de base ( null )
Pareja() {}

// constructror parametrizado
Pareja(double x, double y) : a(x), b(y) {}

// mtodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};

// implementacin de los mtodos de la clase Pareja
//
double Pareja::getA() { return a; }
double Pareja::getB() { return b; }
void Pareja::setA(double n) { a = n; }
void Pareja::setB(double n) { b = n; }

//------------------------
class Suma : public Pareja
{
// atributos de Suma
double resultado;

public:
// constructor
Suma(double a, double b) : Pareja(a, b) {}

// mtodos de Suma
double calcular();
};

// implementacin de Suma
//
double Suma::calcular() { return getA() + getB(); }


//------------------------
int main()
{
Suma s(80, 100);
cout << s.getA() << " + " << s.getB() << " = " <<
s.calcular() << endl;
cin.get();
return 0;
}
Destructores[editar]
Un destructor es un mtodo que pertenece a una clase y el cual (en C++) debe
tener el mismo nombre de la clase a la que pertenece. A diferencia de los otros
mtodos de la clase, un destructor deber ser del tipo void, es decir, el mismo no
regresar valor alguno. Para diferenciar a un mtodo destructor de un mtodo
constructor, al nombre del destructor se le debe anteponer el caracter ~ (Alt +
126).
El objetivo principal del destructor es el de retirar de la memoria al objeto, o sea,
el destructor hace todo lo contrario que el constructor.
Los destructores suelen usarse para liberar memoria que haya sido solicitada por
el objeto a travez de las ordenes malloc(), new, etc. En tales casos se deber
incluir dentro del mtodo destructor la orden free, delete, etc., segn sea el caso.
// clase Pareja con constructor y destructor
class Pareja
{
// atributos
double a, b;

public:
// constructor de base ( nulo )
Pareja() {}

// constructor parametrizado
Pareja(double x, double y) : a(x), b(y) {}

// destructor
~Pareja() {}

// mtodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};
Sobrecarga de Operadores
Programacin en C++/Sobrecarga de Operadores
Contenidos
[ocultar]
1 Sobrecarga de operadores
2 Mi primer sobrecarga
3 Sintaxis general
4 Sobrecarga permitida de operadores
5 Sobrecarga del operador << ( ostream )
6 Sobrecarga del operador >> ( istream )
7 Operadores amigos ( friend )
8 Sobrecarga de operadores dentro de una clase
Sobrecarga de operadores[editar]
La sobrecarga de operadores es uno de los mecanismos que nos permite ampliar las
capacidades de los lenguajes de programacin orientados a objetos. En C++, la declaracin y
definicin de una sobrecarga de operador es muy similar a la declaracin y definicin de una
funcin cualquiera. El ejemplo ms sencillo de una sobrecarga de operadores nos lo da el
lenguaje mismo, es decir, en una operacin aritmtica (por ejemplo, una suma ) el compilador
determina el tipo de operacin requerida de acuerdo con el tipo de datos involucrados. Vamos
a suponer que se tienen las variables: int A, B; double X, Y; int R; y las siguientes
instrucciones:
R = A + B;
R = A + X;
R = X + Y;
Ahora bien:
en el primer caso el compilador determina que el tipo de operacin requerida es una suma
de enteros debido a que los dos miembros ( A y B ) de la suma son del tipo entero.
en el segundo caso parece ser que las cosas no son tan claras, ya que en este los
miembros involucrados en la suma son de tipos diferentes, sin embargo el compilador
determinar el tipo de operacin requerida y depositar en el resultado ( R )el valor
resultante redondeado.
en el tercero y ltimo de los casos el compilador determina que el tipo de operacin
requerida es una suma de reales debido a que los dos miembros ( X e Y ) de la suma son
del tipo double. Tambin en este caso el resultado de la suma se redondea antes de
ponerlo en R.
Mi primer sobrecarga[editar]
Para poner un ejemplo prctico de sobrecarga del operador de suma ( + ) vamos a considerar
el caso de la clase pareja mostrada en seguida:
class Pareja {
public:
double a, b;

// constructor parametrizado
Pareja(const double a,const double b)
{
this->a = a;
this->b = b;
}
};

int main()
{
Pareja A(50, 75 );
Pareja B(150, 175 );
Pareja C = A + B;

return 0;
}
Si usted trata de compilar el programa anterior descubrir que el compilador se queja, es
decir, el compilador no sabe que hacer en el caso de la instruccin Pareja C = A + B; aunque
es evidente que se trata de la declaracion del objeto C y que el mismo se espera que sea igual
a la suma de los objetos A y B. El error se debe al hecho de que el tipo Pareja es en realidad
una clase y no un tipo primitivo y, en consecuencia, se debe de adiestrar al mismo compilador
para que ste sepa de que manera hara la suma de dos objetos del tipo Pareja. As, para
solucionar el error vamos a sobrecargar el operador + para trabajar la suma de dos de dichos
objetos. Vamos:
// Titulo..: programa sobrecarga01.cpp
// Objetivo: demostracin de sobrecarga de operadores
// Autor...: Oscar E. Palacios
#include <iostream>
using namespace std;

class Pareja {
public:
double a, b;

// constructor parametrizado
Pareja(const double a,const double b)
{
this->a = a;
this->b = b;
}
};

// Sobrecarga del operador +
Pareja& operator +(const Pareja &p1,const Pareja &p2)
{
return *(new Pareja(p1.a + p2.a, p1.b + p2.b) );
}

int main()
{
Pareja A(50, 75 );
Pareja B(150, 175 );
Pareja C = A + B;

cout << "A = " << A.a << ',' << A.b << "\n";
cout << "B = " << B.a << ',' << B.b << "\n";
cout << "C = " << C.a << ',' << C.b << "\n";

return 0;
}
Sintaxis general[editar]
Tal y como usted lo habr notado, la declaracin de sobrecarga en el programa anterior es lo
ms parecido a una funcin, es decir, la sintaxis general para sobrecargar uno operador
cualquiera es:
tipo operator + (lista de parmetros);
en donde,
1. tipo se refiere al tipo regresado por el operador
2. operator es una palabra reservada y debe aparecer en toda declaracin de sobrecarga
de operadores
3. el simbolo + est en representacin de cualquier operador
4. lista de parmetros indica los argumentos sobre los que operarar la funcin de
sobrecarga
Nota: en el caso de que el operador sobrecargado se hace para una clase especfica la
sintaxis se extiende de la siguiente manera:
tipo nombre_clase::operator + (lista de parmetros);
Regresando al caso de la clase Pareja, especficamente al operador + de sobrecarga para
dicha clase, nos damos cuenta que dicho operador opera sobre dos objetos de dicha clase y
tambin devuelve un resultado de la misma clase. Esto es lo ms recomendable ya que si
usted recuerda el compilador regresa un resultado entero si es que (por ejemplo) se le da una
instruccin como: R = 100 + 23;. En todo caso, el resultado devuelto por los operadores
sobrecargados es responsabilidad del que esta programando
Sobrecarga permitida de operadores[editar]
En C++ no es posible sobrecargar todos los operadores, pero al menos la mayora de ellos s.
Los operadores que no se pueden sobrecargar son: operadores de directivas de
procesador #, ## ; Selector directo de componente . ; operador para valores por defecto de
funciones de clase : ; Operador de acceso a mbito :: ; Operador de indireccin de puntero-a-
miembro .* ; Condicional ternario ?; sizeof y typeid.
Sobrecarga del operador << ( ostream )[editar]
Normalmente cuando se escribe una clase y se desea que el stream estndar de salida
( cout ) pueda mostrar una representacin de su valor se debe de sobrecargar el operador <<.
Para mostrar un ejemplo retomemos el programa sobrecarga01.cpp ( visto arriba ), en el
mismo se imprimen por medio de cout los miembros ( a y b ) de los objetos A, B y C.
cout << "A = " << A.a << ',' << A.b << "\n";
cout << "B = " << B.a << ',' << B.b << "\n";
cout << "C = " << C.a << ',' << C.b << "\n";
Usted puede ver cmo para cada uno de los miembros de los objetos se debe de usar el
operador de direccin ( . ), pues bien, nuestro objetivo es lograr que dado un objeto de la clase
Pareja ste pueda ser desplegado por cout y para ello haremos la sobrecarga de operador <<
con el fin de que pueda operar con objetos de la clase mencionada. Veamos:
// Titulo..: programa sobrecarga03.cpp
// Objetivo: demostracin de sobrecarga de operadores
// Autor...: Oscar E. Palacios
#include <iostream>
using namespace std;

class Pareja {
public:
double a, b;

// constructor parametrizado
Pareja(const double a,const double b)
{
this->a = a;
this->b = b;
}
};

// Sobrecarga del operador +
Pareja& operator +(const Pareja &p1,const Pareja &p2)
{
return *(new Pareja(p1.a + p2.a, p1.b + p2.b) );
}

// Sobrecarga del operador << para la clase Pareja
ostream& operator << (ostream &o,const Pareja &p)
{
o << "(" << p.a << ", " << p.b << ")";
return o;
}

int main()
{
Pareja A(50, 75 );
Pareja B(150, 175 );
Pareja C = A + B;

cout << "A = " << A << "\n";
cout << "B = " << B << "\n";
cout << "C = " << C << "\n";

return 0;
}
Sobrecarga del operador >> ( istream )[editar]
As como el operador << debe ser sobrecargado, lo mismo es cierto para el operador >> para
poder ser usado con elstream estndar de entrada ( cin ). Retomaremos nuevamente a la
clase Pareja para dar un ejemplo.
// Titulo..: programa sobrecarga03.cpp
// Objetivo: demostracin de sobrecarga de operadores
// Autor...: Oscar E. Palacios
#include <iostream>
using namespace std;

// inserte aqu la clase Pareja y los operadores sobrecargados vistos
// en el programa anterior. Se deber agregar un constructor en la
clase Pareja como el siguiente:
/*Pareja()
{
this->a=0;
this->b=0;
}*/

// Sobrecarga del operador >> para la clase Pareja
istream& operator >> (istream &i, Pareja &p)
{
cout << "Introducir valores para ( a, b) : ";
i >> p.a >> p.b;
i.ignore();
return i;
}

int main()
{
Pareja A(50, 75 );
Pareja B;
cin >> B;
Pareja C = A + B;

cout << "A = " << A << "\n";
cout << "B = " << B << "\n";
cout << "C = " << C << "\n";

return 0;
}
Operadores amigos ( friend )[editar]
Un operador amigo, al igual que una funcin amiga, es aquel que an cuando no es miembro
de una clase tiene todos los privilegios de acceso a los miembros de dicha clase.
En la sobrecarga de los operadores +, << y >>para la clase Pareja de los programas
anteriores, se puede notar que dichos operadores no son parte de la clase Pareja, sino que
ms bien stos operan sobre objetos de dicha clase y es a travs de dichos objetos que
pueden manipular a los miembros de la clase. Ahora bien, no hemos tenido ningn problema
debido a que todos los miembros de Pareja han sido declarados como pblicos (public:), pero
qu sucede si un operador o una funcin que no sea parte de la clase trata de acceder a los
miembros privados o protegidos de sta? En estos casos, el compilador reportara el error
indicando que tal o cual miembro es privado dentro de cierto contexto.
Si queremos que un operador o funcin que no es miembro de una clase pueda acceder a los
miembros pblicos, privados o protegidos deberemos declarar a dicho operador o funcin
como amigo (friend) dentro de la clase especfica. Para mostrar un ejemplo modificaremos la
clase Pareja, donde sus atributos sern privados.
// Titulo..: programa sobrecarga04.cpp
// Objetivo: demostracin de sobrecarga de operadores
// Autor...: Oscar E. Palacios
#include <iostream>
using namespace std;

class Pareja {

private:
double a, b;

public:
// constructor parametrizado
Pareja(const double a,const double b)
{
this->a = a;
this->b = b;
}

friend Pareja& operator +(const Pareja &p1,const Pareja &p2);
friend ostream& operator << (ostream &o,const Pareja &p);
};

// Sobrecarga del operador + para la clase Pareja
Pareja& operator +(const Pareja &p1,const Pareja &p2)
{
return *(new Pareja(p1.a + p2.a, p1.b + p2.b) );
}

// Sobrecarga del operador << para la clase Pareja
ostream& operator << (ostream &o,const Pareja &p)
{
o << "(" << p.a << ", " << p.b << ")";
return o;
}

int main()
{
Pareja A(50, 75 );
Pareja B(150, 175 );
Pareja C = A + B;

cout << "A = " << A << "\n";
cout << "B = " << B << "\n";
cout << "C = " << C << "\n";

return 0;
}
Sobrecarga de operadores dentro de una clase[editar]
Tal y como hemos dicho antes, los operadores que hemos sobrecargado para la clase Pareja (
de los ejemplos anteriores ) no son parte de la clase, pero en la mayora de las veces se ver
que los operadores para una clase especfica se deben sobrecargar dentro de la misma clase,
es decir, dichos operadores sern miembros de la clase. Antes de sobrecargar cualquier
operador para una clase se deben tener en cuenta los siguientes factores:
1. Los operadores binarios se declaran con un solo parmetro, ya que el primer
parmetro es pasado por el programa como this, es decir, un puntero al mismo
objeto.
2. Los operadores unarios se declaran sin paramtros, ya que el nico parmetro es
pasado por el programa como this.
Nota:
Los operadores binarios son aquellos que poseen dos partes ( izquierda y
derecha),
por ejemplo, una operacin de suma requiere dos operandos ( o1 + o2 ).

Los operadores unarios son aquellos que poseen solo una parte, por
ejemplo, una operacin
de incremento ( o1 ++ ).
Con el propsito de ver un ejemplo prctico vamos a retomar una vez ms la tan famosa clase
Pareja, salvo que en esta ocasin vamos a sobrecargar dentro de la misma a los operadores
binarios: + (suma), - (resta), *(multiplicacin) y / (divisin); el operador de asignacin (=); el
operador de incremento (++) y el operador de comparacin (==).
// Programa: sobrecarga05.cpp
// Objetivo: mostrar sobrecarga de operadores
// Autor...: Oscar Edmundo Palacios.
#include <iostream>

using namespace std;

class Pareja {

private:
int a, b;

public:
// constructor base
Pareja() : a(0), b(0) {}

// constructor parametrizado
Pareja(const int a,const int b) {
this->a = a;
this->b = b;
}

// constructor de copia
Pareja(const Pareja&);

// operadores miembros
Pareja& operator + (const Pareja &p);
Pareja& operator - (const Pareja &p);
Pareja& operator * (const Pareja &p);
Pareja& operator / (const Pareja &p);
Pareja& operator = (const Pareja &p);
Pareja& operator ++();
bool operator ==(const Pareja &p) const;

// operadores no miembros
friend ostream& operator << (ostream &o,const Pareja &p);
friend istream& operator >> (istream &o, Pareja &p);
};

// implementacion de los operadores para la clase Pareja
//....................................
Pareja::Pareja(const Pareja &p)
{
*this=p;
}
//....................................
Pareja& Pareja::operator + (const Pareja &p)
{
this->a += p.a;
this->b += p.b;
return *this;
}
//....................................
Pareja& Pareja::operator - (const Pareja &p)
{
this->a -= p.a;
this->b -= p.b;
return *this;
}
//....................................
Pareja& Pareja::operator * (const Pareja &p)
{
this->a *= p.a;
this->b *= p.b;
return *this;
}
//....................................
Pareja& Pareja::operator / (const Pareja &p)
{
if (p.a != 0) this->a /= p.a;
if (p.b != 0) this->b /= p.b;
return *this;
}
//....................................
Pareja& Pareja::operator = (const Pareja &p)
{
if(this!=&p){ //Comprueba que no se est intentanod igualar un
objeto a s mismo
if (p.a != 0) this->a = p.a;
if (p.b != 0) this->b = p.b;
}
return *this;
}

//....................................
Pareja& Pareja::operator ++ ()
{
this->a ++;
this->b ++;
return *this;
}

//....................................
bool Pareja::operator == (const Pareja &p) const
{
return this->a == p.a && this->b == p.b;
}

// implemetacin de operadores no miembros
ostream& operator << (ostream &o,const Pareja &p)
{
o << "(" << p.a << ", " << p.b << ")";
return o;
}

istream& operator >> (istream &i, Pareja &p)
{
cout << "Introducir valores para ( a, b) :";
i >> p.a >> p.b;
i.ignore();
return i;
}


// prueba para la clase Pareja
int main()
{
Pareja A(50, 75);
Pareja B(100, 15);
Pareja C;

cout << "A = " << A << "\n";
cout << "B = " << B << "\n";
cout << "........................." << endl;
C = A * B;
cout << "A = " << A << "\n";
cout << "C = " << C << endl;
cout << "........................." << endl;

++C;
cout << "C = " << C << endl;
cout << "A == B " << ( (A==B) ? "Si": "No" );
cin.get();
return 0;
}
Herencia
Programacin en C++/Herencia
Editores:

Sobrecarga de Operadores Funciones virtuales
Contenidos
[ocultar]
1 Introduccin
2 INTRODUCIENDO LA HERENCIA.
3 CONTROL DE ACCESO DE LA CLASE BASE.
o 3.1 USANDO MIEMBROS PROTEGIDOS.
o 3.2 USANDO PROTECTED PARA LA HERENCIA DE UNA CLASE BASE.
o 3.3 REVISANDO public, protected, y private
o 3.4 HEREDANDO MULTIPLES CLASES BASE
o 3.5 CONSTRUCTORES, DESTRUCTORES, Y HERENCIA
o 3.6 PASANDO PARAMETROS A LOS CONSTRUCTORES DE LA CLASE BASE
o 3.7 GARANTIZANDO ACCESO
o 3.8 LEYENDO GRAFICOS DE HERENCIA EN c++
o 3.9 CLASES BASE VIRTUALES
Introduccin[editar]
La 'herencia' es una de las piedras angulares de la POO ya que sta permite la creacin de
clasificaciones jerrquicas. Con la herencia, es posible crear una clase general que defina
tratos comunes a una serie de elementos relacionados. Esta clase podra luego ser heredada
por otras clases ms especficas, cada una agregando solo aquellas cosas que son nicas
para la clase 'heredera'.
En terminologa estndar C++, una clase que es heredada es referida como la clase 'base'. La
clase que efecta la herencia es llamada la clase 'derivada'. Adems, una clase derivada
puede ser usada como una clase base por otra clase derivada. De esta manera, una jerarqua
multicapa de clases puede ser lograda.
INTRODUCIENDO LA HERENCIA.[editar]
C++ soporta herencia permitiendo a una clase incorporar otra clase dentro de su declaracin.
Antes de discutir los detalles y la teora, se procede a comenzar por un ejemplo de herencia.
La siguiente clase, llamada 'VehiculoRodante', define muy ampliamente a vehculos que viajan
por la carretera. Este almacena el numero de ruedas que un vehculo tiene y el numero de
pasajeros que puede llevar.
Un regla sencilla para recordar esto es: "Una clase derivada hereda de una clase base"
// Definicin de una clase base para vehiculos
class VehiculoRodante
{
public:
// CICLO DE VIDA
/* En este lugar se sitan los constructores, los destructores, y/o
los constructores copia */

// OPERADORES
/* Aqu van los mtodos que se apliquen sobre operadores */

// OPERACIONES
/* Aqu van los mtodos de esta clase que no sean ni de acceso ni de
peticin o tratamiento */

// ACCESO
/* Aqu van las funciones de acceso a los datos miembro o variables
propias del objeto */

/*
* Funcin 'set_ruedas'
* Recibe: num como int
* Devuelve: void
* Asigna al dato miembro 'mRuedas' el valor 'num'
*/
void set_ruedas(int num)
{
this->mRuedas = num;
}

/*
* Funcin 'get_ruedas'
* Recibe: void
* Devuelve: int
* Devuelve el valor que hay dentro del dato miembro 'mRuedas'
*/
int get_ruedas(void)
{
return this->mRuedas;
}

/*
* Funcin 'set_pasajeros'
* Recibe: num como int
* Devuelve: void
* Asigna al dato miembro 'mPasajeros' el valor 'num'
*/
void set_pasajeros(int num)
{
this->mPasajeros = num;
}

/*
* Funcin 'get_pasajeros'
* Recibe: void
* Devuelve: int
* Devuelve el valor que hay dentro del dato miembro 'mPasajeros'
*/
int get_pasajeros(void)
{
return this->mPasajeros;
}

// PETICIONES/TRATAMIENTOS
/* Aqu van las funciones del tipo "Is", que generalmente devuelven
true/false */

private:
/* Generalmente en 'private' se sitan los datos miembros */
int mRuedas;
int mPasajeros;
};
Se puede usar esta amplia definicin de un vehculo rodante para ayudar a definir tipos
especficos de vehculos. Por ejemplo, el fragmento de cdigo mostrado aqui podra usarse
para ser heredado por una clase derivada llamada 'Camion'.
// Definicin de una clase 'Camion' derivada de la clase base
'VehiculoRodante'.
class Camion : public VehiculoRodante
{

public:
// CICLO DE VIDA
/* En este lugar se sitan los constructores, los destructores, y/o
los constructores copia */

// OPERADORES
/* Aqu van los mtodos que se apliquen sobre operadores */

// OPERACIONES
/* Aqu van los mtodos de esta clase que no sean ni de acceso ni de
peticin o tratamiento */

// ACCESO
/* Aqu van las funciones de acceso a los datos miembro o variables
propias del objeto */

/*
* Funcin 'set_carga'
* Recibe: size como int
* Devuelve: void
* Asigna al dato miembro 'mCarga' el valor 'size'
*/
void set_carga(int size)
{
this->mCarga = size;
}

/*
* Funcin 'get_carga'
* Recibe: void
* Devuelve: int
* Devuelve el valor que hay dentro del dato miembro 'mCarga'
*/
int get_carga(void)
{
return this->mCarga;
}


/*
* Funcin 'Mostrar'
* Recibe: void
* Devuelve: void
* Muestra por pantalla las ruedas, pasajeros y la capacidad de carga
del objeto 'Camion'
*/
void Mostrar(void);

// PETICIONES/TRATAMIENTOS
/* Aqu van las funciones del tipo "Is", que generalmente devuelven
true/false */

private:
/* Generalmente en 'private' se sitan los datos miembros */
int mCarga;
};
Como 'Camion' hereda de 'VehiculoRodante', 'Camion' incluye todo de 'vehiculo_rodante'.
Entonces agrega 'carga' a la misma, en conjunto con las funciones miembros que trabajen
sobre este dato.
Ntese como 'VehiculoRodante' es heredado. La forma general para la herencia se muestra
aqu:
class ClaseDerivada : acceso ClaseBase
{
//cuerpo de la nueva clase
}
Aqu, 'acceso' es opcional. Sin embargo, si se encuentra presente, debe ser 'public', 'private', o
'protected'. Se aprender ms sobre estas opciones ms tarde, por ahora para todas las
clases heredadas se usar el acceso 'public'. Usar public significa que todos los miembros
pblicos de la clase base sern tambin miembros pblicos de la clase derivada. Por tanto, en
el ejemplo anterior, miembros de la clase 'Camion' tienen acceso a los miembros pblicos de
'VehiculoRodante', justo como si ellos hubieran sido declarados dentro de 'Camion'. Sin
embargo, 'camion' no tiene acceso a los miembros privados de 'VehiculoRodante'. Por
ejemplo, 'Camion' no tiene acceso a ruedas.
He aqu un programa que usa herencia para crear dos subclases de 'VehiculoRodante'. Una
es 'Camion' y la otra es 'Automovil'.
// Programa que demuestra la herencia.

// INCLUDES DE SISTEMA
//
#include <iostream>

// INCLUDES DEL PROYECTO
//

// INCLUDES LOCALES
//

// DECLARACIONES
//

// Definicin de una clase base para vehiculos
class VehiculoRodante
{
public:
// CICLO DE VIDA
/* En este lugar se sitan los constructores, los destructores, y/o
los constructores copia */

// OPERADORES
/* Aqu van los mtodos que se apliquen sobre operadores */

// OPERACIONES
/* Aqu van los mtodos de esta clase que no sean ni de acceso ni de
peticin o tratamiento */

/*
* Funcin 'set_ruedas'
* Recibe: num como int
* Devuelve: void
* Asigna al dato miembro 'mRuedas' el valor 'num'
*/
void set_ruedas(int num)
{
this->mRuedas = num;
}

/*
* Funcin 'get_ruedas'
* Recibe: void
* Devuelve: int
* Devuelve el valor que hay dentro del dato miembro 'mRuedas'
*/
int get_ruedas(void)
{
return this->mRuedas;
}

/*
* Funcin 'set_pasajeros'
* Recibe: num como int
* Devuelve: void
* Asigna al dato miembro 'mPasajeros' el valor 'num'
*/
void set_pasajeros(int num)
{
this->mPasajeros = num;
}

/*
* Funcin 'get_pasajeros'
* Recibe: void
* Devuelve: int
* Devuelve el valor que hay dentro del dato miembro 'mPasajeros'
*/
int get_pasajeros(void)
{
return this->mPasajeros;
}

// PETICIONES/TRATAMIENTOS
/* Aqu van las funciones del tipo "Is", que generalmente devuelven
true/false */

private:
/* Generalmente en 'private' se sitan los datos miembros */
int mRuedas;
int mPasajeros;
};

// Definicin de una clase 'Camion' derivada de la clase base
'VehiculoRodante'.
class Camion : public VehiculoRodante
{

public:
// CICLO DE VIDA
/* En este lugar se sitan los constructores, los destructores, y/o
los constructores copia */

// OPERADORES
/* Aqu van los mtodos que se apliquen sobre operadores */

// OPERACIONES
/* Aqu van los mtodos de esta clase que no sean ni de acceso ni de
peticin o tratamiento */

// ACCESO
/* Aqu van las funciones de acceso a los datos miembro o variables
propias del objeto */

/*
* Funcin 'set_carga'
* Recibe: size como int
* Devuelve: void
* Asigna al dato miembro 'mCarga' el valor 'size'
*/
void set_carga(int size)
{
this->mCarga = size;
}

/*
* Funcin 'get_carga'
* Recibe: void
* Devuelve: int
* Devuelve el valor que hay dentro del dato miembro 'mCarga'
*/
int get_carga(void)
{
return this->mCarga;
}


/*
* Funcin 'Mostrar'
* Recibe: void
* Devuelve: void
* Muestra por pantalla las ruedas, pasajeros y la capacidad de carga
del objeto 'Camion'
*/
void Mostrar(void);

// PETICIONES/TRATAMIENTOS
/* Aqu van las funciones del tipo "Is", que generalmente devuelven
true/false */

private:
/* Generalmente en 'private' se sitan los datos miembros */
int mCarga;
};

void Camion::Mostrar(void)
{
std::cout << "ruedas: " << this->get_ruedas() << std::endl;
std::cout << "pasajeros: " << this->get_pasajeros() << std::endl;
std::cout << "Capacidad de carga en pies cbicos: " << this-
>get_carga() << std::endl;
}

/*
* Este enumerador sirve para definir diferentes tipos de automvil
*/
enum tipo {deportivo, berlina, turismo};

// Definicin de una clase 'Automovil' derivada de la clase base
'VehiculoRodante'.
class Automovil : public VehiculoRodante
{
public:
// CICLO DE VIDA
/* En este lugar se sitan los constructores, los destructores, y/o
los constructores copia */

// OPERADORES
/* Aqu van los mtodos que se apliquen sobre operadores */

// OPERACIONES
/* Aqu van los mtodos de esta clase que no sean ni de acceso ni de
peticin o tratamiento */

// ACCESO
/* Aqu van las funciones de acceso a los datos miembro o variables
propias del objeto */

/*
* Funcin 'set_tipo'
* Recibe: t como tipo
* Devuelve: void
* Asigna al dato miembro 'mTipoDeAutomovil' el valor 't'
*/
void set_tipo(tipo t)
{
this->mTipoDeAutomovil = t;
}

/*
* Funcin 'get_tipo'
* Recibe: void
* Devuelve: tipo
* Devuelve el valor que hay dentro del dato miembro
'mTipoDeAutomovil'
*/
enum tipo get_tipo(void)
{
return this->mTipoDeAutomovil;
};

/*
* Funcin 'Mostrar'
* Recibe: void
* Devuelve: void
* Muestra por pantalla las ruedas, pasajeros y la capacidad de carga
del objeto 'Camion'
*/
void Mostrar(void);

private:
enum tipo mTipoDeAutomovil;
};

void Automovil::Mostrar(void)
{
std::cout << "ruedas: " << this->get_ruedas() << std::endl;
std::cout << "pasajeros: " << this->get_pasajeros() << std::endl;
std::cout << "tipo: ";

switch(this->get_tipo())
{
case deportivo:
std::cout << "deportivo";
break;

case berlina:
std::cout << "berlina";
break;

case turismo:
std::cout << "turismo";
}
std::cout << std::endl;
}

/*
* Funcin 'main'
* Recibe: void
* Devuelve: int
* El cdigo es una posible implementacin para clarificar el uso
efectivo de clases bases y clases derivadas.
* Muestra por pantalla valores de la clase base y de las clases
derivadas.
*/
int main(void)
{
Camion Camion1;
Camion Camion2;
Automovil Automovil1;

Camion1.set_ruedas(18);
Camion1.set_pasajeros(2);
Camion1.set_carga(3200);

Camion2.set_ruedas(6);
Camion2.set_pasajeros(3);
Camion2.set_carga(1200);

Camion1.Mostrar();
std::cout << std::endl;
Camion2.Mostrar();
std::cout << std::endl;

Automovil1.set_ruedas(4);
Automovil1.set_pasajeros(6);
Automovil1.set_tipo(tipo::deportivo);

Automovil1.Mostrar();

return 0;
}
La salida de este programa se muestra a continuacin:
ruedas: 18
pasajeros: 2
Capacidad de carga en pies cbicos: 3200
ruedas: 6
pasajeros: 3
Capacidad de carga en pies cbicos: 1200
ruedas: 4
pasajeros: 6
tipo: deportivo
Como este programa muestra, la mayor ventaja de la herencia es que permite crear una clase
base que puede ser incorporada en clases ms especficas. De esta manera, cada clase
derivada puede ser precisamente ajustada a las propias necesidades y aun siendo parte de la
clasificacin general.
Por otra parte, ntese que ambos, 'Camion' y 'Automovil', incluyen una funcin miembro
llamada 'Mostrar()', la cual muestra informacin sobre cada objeto. Esto ilustra un aspecto del
polimorfismo. Como cada funcin 'Mostrar()' esta enlazada con su propia clase, el compilador
puede fcilmente indicar cul llamar para cualquier objeto dado.
Ahora que se ha visto los procedimientos bsicos por los cules una clase hereda de otra, se
examinar la herencia en detalle.
CONTROL DE ACCESO DE LA CLASE BASE.[editar]
Cuando una clase hereda de otra, los miembros de la clase base se convierten en miembros
de la clase derivada. El estado de acceso de los miembros de la clase base dentro de la clase
derivada es determinado por el especificador de acceso usado para heredar la clase base. El
especificador de acceso de la clase base debe ser 'public', 'private' o 'protected'. Si el
especificador de acceso no es usado, entonces se usara private por defecto si la clase
derivada es una clase. Si la clase derivada es una 'struct' entonces 'public' es el acceso por
defecto por la ausencia de un expecificador de acceso explcito. Examinemos las
ramificaciones de usar accesos public o private. ( El especificador 'protected' se describe en la
prxima seccin.)
Cuando una clase base es heredada como 'public', todos los miembros pblicos de la clase
base se convierten en miembros de la clase derivada. En todos los casos, los elementos
privados de la clase base se mantienen de esa forma para esta clase, y no son accesibles por
miembros de la clase derivada. Por ejemplo, en el siguiente programa, los miembros pblicos
de 'base' se convierten en miembros publics de 'derivada'. Encima, son accesibles por otras
partes del programa.
#include <iostream>
using namespace std;

class base {

int i, j;

public:
void set(int a, int b) { i = a; j = b; }
void mostrar() { cout << i << " " << j << "\n"; }
};

class derivada : public base {

int k;

public:
derivada(int x) { k = x; }
void mostrar_k() { cout << k << "\n"; }
};

int main()
{
derivada obj(3);

obj.set(1, 2); // accesar a miembro de base
obj.mostrar(); // accesar a miembro de base

obj.mostrar_k(); // usa miembro de la clase derivada

return 0;
}

Como set() y mostrar() son heredadas como 'public', ellas pueden ser llamadas en un objeto
del tipo 'derivada' desde main(). Como i y j son especificadas como 'private', ellas se
mantienen privadas a base.
El opuesto de herencia publica es herencia privada. Cuando la clase base es heredad como
privada, entonces todos los miembros pblicos de la clase base se convierten en miembros
privados de la clase derivada. Por ejemplo, el programa mostrado a continuacin no
compilara, porque set() y mostrar() son ahora miembros privados de 'derivada', y por ende no
pueden ser llamados desde main().
TIP:"Cuando una clase base es heredada como 'private' sus miembros
pblicos se
convierten en miembros privados de la clase derivada."
// Este programa no compilara.
#include <iostream>

using namespace std;

class base {

int i, j;

public:
void set(int a, int b) { i = a; j = b; }
void mostrar() { cout << i << " " << j << "\n"; }
};

// Miembros publicos de 'base' son privados en 'derivada'
class derivada : private base {

int k;

public:

derivada(int x) { k = x; }
void mostrar_k() { cout << k << "\n"; }
};

int main()
{

derivada obj(3);

obj.set(1, 2); // Error, no se puede acceder a set()
obj.mostrar(); // Error, no se puede acceder a mostrar()

return 0;
}

La clave a recordar es que cuando una clase base es heredada como 'private', los miembros
pblicos de la clase base se convierten en miebros privados de la clase derivada. Esto
significa que aun ellos son accesibles por miembros de la clase derivada, pero no pueden ser
accedidos por otras partes de su programa.

USANDO MIEMBROS PROTEGIDOS.[editar]

En adicin a public y private, un miembro de la clase puede ser declarado como protegido.
Adems, una clase base puede ser heredada como protegida. Ambas de estas acciones son
cumplidas por el especificador de acceso 'protected'. La palabra clave 'protected' esta incluida
en C++ para proveer gran flexibilidad para el mecanismo de herencia.
Cuando un miembro de una clase es declarado como 'protected', ese miembro, no es
accesible a otros elementos no-miembros de la clase en el programa. Con una importante
excepcin, el acceso a un miembro protegido es lo mismo que el acceso a un miembro
privado, este puede ser accedido solo por otros miembros de la clase de la cual es parte. La
nica excepcin a esta regla es cuando un miembro protegido es heredado. En este caso, un
miembro protegido difiere sustancialmente de uno privado.
Como debe conocer, un miembro privado de una clase base no es accesible por cualquier otra
parte de su programa, incluyendo cualquier clase derivada. Sin embargo, los miembros
protegidos se comportan diferente. Cuando una clase base es heredada como publica, los
miembros protegidos en la clase base se convierten en miembros protegidos de la clase
derivada, y 'son' accesibles a la clase derivada. Adems, usando 'protected' usted puede crear
miebros de clases que son privados para su clase, pero que aun asi pueden ser heredados y
accedidos por una clase derivada.
Considere este programa de ejemplo:
#include <iostream>

using namespace std;

class base {

protected:
int i, j; // privados a base, pero accesibles a derivada.

public:
void set(int a, int b) { i = a; j = b; }
void mostrar() { cout << i << " " << j << "\n"; }
};

class derivada : public base {

int k;

public:
// derivada puede accesar en base a 'j' e 'i'
void setk() { k = i * j; }
void mostrark() { cout << k << "\n"; }
};

int main()
{
derivada obj;

obj.set(2, 3); // OK, conocido por derivada.
obj.mostrar(); // OK, conocido por derivada.

obj.setk();
obj.mostrark();

return 0;
}

Aqu, porque 'base' es heredada por 'derivada' como pblica, y porque j e i son declaradas
como protegidas, la funcin setk() en 'derivada' puede acceder a ellas. Si j e i hubieran sido
declaradas como privadas por 'base', entonces 'derivada' no tuviera acceso a ellas, y el
programa no compilara.
RECUERDE: El especificador 'protected' le permite crear un miembro de la clase que es
accesible desde la jerarqua de la clase, pero de otra manera es privado.

Cuando una clase derivada es usada como clase base para otra clase derivada, entonces
cualquier miembro protegido de la clase base inicial que es heredado ( como public ) por la
primera clase derivada puede ser heredado nuevamente, como miembro protegido, por una
segunda clase derivada. Por ejemplo, el siguiente programa es correcto, y derivada2 tiene, de
hecho, acceso a 'j' e 'i':

#include <iostream>
using namespace std;

class base {

protected:
int i, j;

public:

void set(int a, int b) { i = a; j = b; }
void mostrar() { cout << i << " " << j << "\n"; }
};

// j e i se heredan como 'protected'
class derivada1 : public base {
int k;

public:

void setk() { k = i*j; } // legal
void mostrark() { cout << k << "\n"; }
};

// j e i se heredan indirectamente a travs de derivada1
class derivada2 : public derivada1 {
int m;

public:
void setm() { m = i-j; } // legal
void mostrarm() { cout << m << "\n"; }
};

int main()
{

derivada1 obj1;
derivada2 obj2;

obj1.set(2, 3);
obj1.mostrar();
obj1.setk();
obj1.mostrark();

obj2.set(3, 4);
obj2.mostrar();
obj2.setk();
obj2.setm();
obj2.mostrark();
obj2.mostrarm();

return 0;
}
Cuando una clase base es heredada como 'private', miembros protegidos de la clase base se
convierten en miembros privados de la clase derivada. Adems, en el ejemplo anterior, si
'base' fuera heredada como 'private', entonces todos los miembros de 'base' se hubieran
vuelto miembros privados de derivada1, significando que ellos no podran estar accesibles a
derivada2. ( Sin embargo, j e i podran aun ser accesibles a derivada1.) Esta situacin es
ilustrada por el siguiente programa, el cual es un error ( y no compilara ). Los comentarios
describen cada error.

// Este programa no compilara.
#include <iostream>
using namespace std;

class base {
protected:
int i, j;

public:

void set(int a, int b) { i = a; j = b; }
void mostrar() { cout << i << " " << j << "\n"; }
};

// Ahora todos los elementos de base son privados en derivada1.
class derivada1 : private base {
int k;

public:
// Esto es legal porque j e i son privadas a derivada1
void setk() { k = i*j; } // OK
void mostrark() { cout << k << "\n"; }
};

// Acceso a j, i, set() y mostrar no heredado
class derivada2 : public derivada1 {
int m;

public:
// Ilegal porque j e i son privadas a derivada1
setm() { m = j-i; } // error
void mostrarm() { cout << m << "\n"; }
};

int main()
{
derivada1 obj1;
derivada2 obj2;

obj1.set(1, 2); // Error, no se puede usar set()
obj1.mostrar(); // Error, no se puede usar show()

obj2.set(3, 4); // Error, no se puede usar set()
obj2.mostrar(); // Error, no se puede usar show()

return 0;
}

Incluso aunque 'base' es heredada como privada por derivada1, derivada2 aun tiene acceso a
los elementos publicos y protegidos de 'base'. Sin embargo, no puede sobrepasar este
privilegio a todo lo largo. Esta es la razon de las partes 'protected' del lenguaje C++. Este
provee un medio de proteger ciertos miembros de ser modificados por funciones no-miembros,
pero les permite ser heredadas.
El especificador 'protected' puede ser usado con estructuras. Sin embargo no puede ser usado
con una 'union' porque la union no puede heredar otra clase o ser heredad. ( Algunos
compiladores aceptaran su uso en una declaracion en una union, pero como las uniones no
pueden participar en la herencia, 'protected' es lo mismo que 'private' en este contexto.)
El especificador 'protected' puede ocurrir en cualquier lugar en la declaracion de una clase,
aunque tipicamente ocurre despues de ( por defecto ) que los miembros privados son
declarados, y antes de los miebros publicos. Ademas, la mayor forma completa de la
declaraciond de una clase es
class nombre-clase {

miembros privados

protected:
miembros protegidos

public:
miembros publicos
};
Por supuesto, la categoria protected es opcional.
USANDO PROTECTED PARA LA HERENCIA DE UNA CLASE BASE.[editar]

Como adicin a especificar el estado protegido para los miembros de una clase, la palabra
clave 'protected' tambien puede ser usada para heredar una clase base. Cuando una clase
base es heredada como protected, todos los miembros publicos y protegidos de la clase base
se convierten en miembros protegidos de la clase derivada. Aqui hay un ejemplo:

// Demuestra la herencia de una clase base protegida
#include <iostream>
using namespace std;

class base {
int i;

protected:
int j;

public:
int k;
void seti(int a) { i = a; }
int geti() { return i; }
};

// heredar 'base' como protected.
class derivada : protected base {

public:
void setj(int a) { j = a; }; // j es protected aqui.
void setk(int a) { k = a; }; // k es tambien protected.
int getj() { return j; }
int getk() { return k; }
};

int main()
{
derivada obj;

/* La proxima linea es ilegal porque seti() es
un miembro protegido de derivada, lo cual lo
hace inaccesible fuera de derivada. */
// obj.seti(10);

// cout << obj.geti(); // ilegal -- geti() es protected.
// obj.k = 10; // tambien ilegal porque k es protected.

// estas declaraciones son correctas
obj.setk(10);
cout << obj.getk() << " ";
obj.setj(12);
cout << obj.getj() << " ";

return 0;
}

Como puede ver leyendo los comentarios en este programa, k,j, seti() y geti() en 'base' se
convierten miembros 'protected' en 'derivada'. Esto significa que ellos no pueden ser
accesados por codigo fuera de 'derivada'. Ademas, dentro de main(), referencias a estos
miembros a traves de obj son ilegales.
REVISANDO public, protected, y private[editar]
Ya que los permisos de acceso que son definidos por 'public', 'protected', y 'private' son
fundamentales para la programacin en C++, volvamos a revisar sus significados.
Cuando una clase miembro es declarada como 'public', esta puede ser accedida por cualquier
otra parte del programa. Cuando un miembro es declarado como 'private', este puede ser
accedido solo por miembros de su clase. Adems, clases derivadas no tienen acceso a
miembros privados de la clase base. Cuando un miembro es declarado como 'protected', este
puede ser accedido solo por miembros de su clase, o por clases derivadas. Adems, protected
permite que un miembro sea heredado, pero que se mantenga privado en la jerarqua de la
clase.
Cuando una clase base es heredada por el uso de 'public', sus miembros publicos se
convierten en miebros publicos de la clase derivada, y sus miembros protected se convierten
en miembros protected de la clase derivada.
Cuando una clase base es heredada por el uso de 'protected', sus miembros publicos y
protegidos se convierten en miembros protected de la clase derivada.
Cuando una clase base es heredada por el uso de 'private', sus miembros publicos y
protegidos se convierten en miebros private de la clase derivada.
En todos los casos, los miembros privados de la clase base se mantienen privados a la clase
base, y no son heredados.
HEREDANDO MULTIPLES CLASES BASE[editar]
Es posible para una clase derivada heredar dos o mas clases base. Por ejemplo, en este corto
programa, derivada hereda de ambas clases base1 y base2:
// Un ejemplo de multiples clases base
#include <iostream>
using namespace std;

class base1 {
protected:
int x;

public:
void showx() { cout << x << "\n"; }
};

class base2 {
protected:
int y;

public:
void showy() { cout << y << "\n"; }
};

// Heredar multiples clases base.
class derivada : public base1, public base2 {

public:
void set(int i, int j) { x= i; y = j; };
};

int main()
{

derivada obj;

obj.set(10, 20); // proveida por derivada.
obj.showx(); // desde base1
obj.showy(); // desde base2

return 0;
}
Como este ejemplo ilustra, para causar que mas de una clase base sea heredad, debe usarse
una lista separada por comas. Ademas, asegurese de usar un especificador de acceso para
cada clase heredada.
CONSTRUCTORES, DESTRUCTORES, Y HERENCIA[editar]
Existen dos importantes preguntas relativas a los constructores y destructores cuando la
herencia se encuentra implicada. Primera, dnde son llamados los constructores y
destructores de las clases base y clases derivadas? Segunda, como se pueden pasar los
parmetros al constructor de una clase base? Esta seccin responde estas preguntas.
Examine este corto programa:
#include <iostream>
using namespace std;

class base {

public:
base() { cout << "Construyendo base\n"; }
~base() { cout << "Destruyendo base\n"; }
};


class derivada : public base {
public:
derivada() { cout << "Construyendo derivada\n"; }
~derivada() { cout << "Destruyendo derivada\n"; }
};

int main()
{
derivada obj;

// no hacer nada mas que construir y destruir obj

return 0;
}
Como el comentario en main() indica, este programa simplemente construye y destruye un
objeto llamado obj, el cual es de la clase 'derivada'. Cuando se ejecuta, este programa
muestra:
Construyendo base Construyendo derivada Destruyendo derivada Destruyendo base
Como puede ver, el constructor de 'base' es ejecutado, seguido por el constructor en
'derivada'. A continuacin ( ya que obj es inmediatamente destruido en este programa), el
destructor en 'derivada' es llamado, seguido por el de 'base'.
El resultado del experimento anterior puede ser generalizado como lo siguiente: Cuando un
objeto de una clase derivada es creado, el constructor de la clase base es llamado primero,
seguido por el constructor de la clase derivada. Cuando un objeto derivada es destruido, su
destructor es llamado primero, seguido por el destructor de la clase base. Vindolo de otra
manera, los constructores son ejecutados en el orden de su derivacin. Los destructores son
ejecutado en orden inverso de su derivacin.
Si lo piensa un poco, tiene sentido que las funciones constructor sean ejecutadas en el orden
de su derivacin. Porque una clase base no tiene conocimiento de las clases derivadas,
cualquier inicializacin que necesite realizar es separada de, y posiblemente un prerequisito a,
cualquier inicializacin realidada por la clase derivada. Adems, esta debe ejecutarse primero.
Asimismo, es bastante sensible que los destructores sean ejecutados en orden inverso a su
derivacin. Ya que la clase base contiene una clase derivada, la destruccion de una clase
base implica la destruccion de su clase derivada. Adems, el constructor derivado debe ser
llamado antes de que el objeto sea completamente destruido.

En el caso de una gran jerarqua de clases ( ej: cuando una clase derivada se convierta en la
base clase de otra clase derivada ), la regla general se aplica: Los constructores son llamados
en orden de su derivacion, los destructores son llamados en orden inverso. Por ejemplo, este
programa
#include <iostream>
using namespace std;

class base {

public:

base() { cout << "construyendo base\n"; }
~base() { cout << "Destruyendo base\n"; }
};

class derivada1 : public base {

public:
derivada1() { cout << "Construyendo derivada1\n"; }
~derivada1() { cout << "destruyendo derivada1\n"; }
};


class derivada2 : public derivada1 {

public:
derivada2() { cout << "Construyendo derivada2\n"; }
~derivada2() { cout << "Destruyendo derivada2\n"; }
};

int main()
{
derivada2 obj;

// construir y destruir obj

return 0;
}
Muestra la salida:
construyendo base
Construyendo derivada1
Construyendo derivada2
Destruyendo derivada2
destruyendo derivada1
Destruyendo base
La misma regla general se aplica en situaciones en que se ven implicadas multiples clases
base. Por ejemplo, este programa
#include <iostream>
using namespace std;

class base1 {

public:
base1() { cout << "Construyendo base1\n"; }
~base1() { cout << "Desstruyendo base1\n"; }
};

class base2 {

public:
base2() { cout << "Construyendo base2\n"; }
~base2() { cout << "Destruyendo base2\n"; }
};

class derivada : public base1, public base2 {

public:
derivada() { cout << "Construyendo derivada\n"; }
~derivada() { cout << "Destruyendo derivada\n"; }
};

int main()
{
derivada obj;

// construir y destruir obj

return 0;
}
Produce la salida:
Construyendo base1
Construyendo base2
Construyendo derivada
Destruyendo derivada
Destruyendo base2
Destruyendo base1
Como puede ver, los constructores son llamados en el orden de su derivacion, de izquierda a
derecha, como se especifico en la lista de herencia en derivada. Los destructores son
llamados en orden inverso, de derecha a izquierda. Esto significa que si base2 fuera
especificada antes de base1 en la lista de derivada, como se muestra aqui:
class derivada: public base2, public base1 {
entonces la salida del programa anterior hubiera sido asi:
Construyendo base2
Construyendo base1
Construyendo derivada
Destruyendo derivada
Destruyendo base1
Derstruyendo base2
PASANDO PARAMETROS A LOS CONSTRUCTORES DE LA CLASE
BASE[editar]
Hasta ahora, ninguno de los ejemplos anteriores han incluido constructores que requieran
argumentos. En casos donde solo el constructor de la clase derivada requiera uno o mas
argumentos, simplemente use la sintaxis estandarizada de parametrizacion del constructor.
Pero, como se le pasan argumentos a un constructor en una clase base? La respuesta es usar
una forma expandida de la declaracion de la clase derivada, la cual pasa argumentos entre
uno o mas constructores de la clase base. La forma general de esta declaracion expandida se
muestra aqui:
constructor-derivada(lista-argumentos) : base1(lista-argumentos),
base2(lista-argumentos),
baseN(lista-argumentos)
{

cuerpo del constructor derivado
}

Aqui, desde base1 hasta baseN son los nombres de las clases base heredadas por la clase
derivada. Notese los dos puntos separando la declaracion del constructor de la clase derivada
de las clases base, y que las clases base estan separadas cada una de la otra por comas, en
el caso de multiples clases base.
Considere este programa de ejemplo:

#include <iostream>
using namespace std;

class base {

protected:
int i;

public:
base(int x) { i = x; cout << "Construyendo base\n"; }
~base() { cout << "Destruyendo base\n"; }
};


class derivada : public base {
int j;

public:
// derivada usa x, y es pasado en consjunto a base
derivada(int x, int y) : base(y)
{ j = x; cout << "Construyendo derivada\n"; }

~derivada() { cout << "Destruyendo derivada\n"; }
void mostrar() { cout << i << " " << j << "\n"; }
};

int main()
{
derivada obj(3, 4);

obj.mostrar(); // muestra 4 3

return 0;
}

Aqui, el constructor en derivada es declarado para que tome 2 parametros, x, y. Sin embargo,
derivada() usa solo x, y es pasada a base(). En general, el constructor de la clase derivada
debe declarar el/los parametro(s) que esta clase requiere, tamnbien cualquiera requerido por
la clase base. Como el ejemplo anterior ilustra, cualquiera de los parametrosr requeridos por la
clase base son pasados a esta en la lista de argumentos de la clase base, especificadas
despues de los dos puntos.
Aqui tenemos un programa de ejemplo que usa multiples clases base:
#include <iostream>
using namespace std;

class base1 {
protected:
int i;

public:
base1(int x) { i = x; cout << "Construyendo base1\n"; }
~base1() { cout << "Destruyendo base1\n"; }
};

class base2 {
protected:
int k;

public:
base2(int x) { k = x; cout << "construyendo base2\n"; }
~base2() { cout << "Destuyendo base2\n"; }
};

class derivada : public base1, public base2 {

int j;

public:
derivada(int x, int y, int z) : base1(y), base2(z)
{ j = x; cout << "construyendo derivada\n"; }

~derivada() { cout << "Destruyendo derivada\n"; }
void mostrar() { cout << i << " " << j << " " << k << "\n"; }
};

int main()
{
derivada obj(3, 4, 5);

obj.mostrar(); // mostrar 3 4 5

return 0;
}
Es importante comprender que los argumentos al constructor de la clase base son pasado via
argumentos al constructor de la clase derivada. Ademas, incluso si el constructor de una clase
derivada no usa ningun argumento, este aun debe declarar uno o mas argumentos si la clase
base toma uno o mas argumentos. En esta situacion, los argumentos pasado a la clase
derivada son simplemente pasados hacia la clase base. Por ejemplo en el siguiente programa,
el constructor en derivada no toma argumentos, pero base1() y base2() lo hacen:
#include <iostream>
using namespace std;

class base1 {

protected:

int i;

public:
base1(int x) { i=x; cout << "Construyendo base1\n"; }
~base1() { cout << "Destruyendo base1\n"; }
};

class base2 {
protected:
int k;

public:
base2(int x) { k=x; cout << "construyendo base2\n"; }
~base2() { cout << "Destruyendo base2\n"; }
};

class derivada : public base1, public base2 {

public:

/* el constructor en derivada no usa parametros,
pero aun asi debe ser declarado para tomarlos
y pasarselos a las clases base.
*/
derivada(int x, int y) : base1(x), base2(y)
{ cout << "Construyendo derivada\n"; }

~derivada() { cout << "Destruyendo derivada\n"; }
void mostrar() { cout << i << "" << k << "\n"; }
};

int main()
{
derivada obj(3, 4);

obj.mostrar(); // mostrar 3 4

return 0;
}

El constructor de la clasde derivada es libre de usar cualquiera de todos los parameteos que
se declara que toma, ya sea que uno o mas sean pasados a una clase base. Viendolo
diferente, solo porque un argumento es pasado a la clase base no declara su uso en la clase
derivada. Por ejemplo, este fragmento es perfectamente valido:
class derivada : public base {
int j;

public:
// derivada usa x, y, y tambien las pasa a base
derivada(int x, int y) : base(x,y)
{ j = x*y; cout << "construyendo derivada\n"; }
// ...
Un punto final a tener en mente cuando se pase argumentos a los constructores de la clase
base: Un argumento siendo pasado puede consistir de cualquier expresion valida en ese
momento, incluyendo llamadas a funciones y variables. Esto es para sostener el hecho de que
C++ permite la inicializacion dinamica.
GARANTIZANDO ACCESO[editar]
Cuando una clase base es heredada como private, todos los miembros de esa clase (public,
protected o private) se convierten en miembros privates de la clase derivada. Sin embargo, en
ciertas circunstancias, podra restaurar uno o mas miembros heredados a su especificacion de
acceso original. Por ejemplo, quizas desee permitir a ciertos miembros publicos de la clase
base tener un estado public en la clase derivada, incluso aunque la clase es heredada como
private. Hay dos maneras de lograr esto. Primero, usted deberia usar una declaracion 'using'
con la clase derivada. Este es el metodo recomendado por los estandares C++ para uso no
nuevo codigo. Sin embargo, una discusion de 'using' se retrasa hasta finales de este libro
donde los 'namespaces' son examinados. ( La primera razon para usar using es para dar
soporte a namespaces. ) La segunda manera para ajustar el acceso a un miembro heredado
es emplear una declaracion de acceso. Las declaraciones de acceso son aun soportadas por
el estandar C++, pero han sido marcadas como deprecadas, lo que significa que ellas no
deben ser usadas para nuevo codigo, Como aun son usadas en codigo existente, una
discusion de las declaraciones de acceso es presentada aqui:

Una declaracion de acceso toma esta forma general:
clase-base::miembro;
La declaracion de acceso es ubicada bajo los apropiados encabezados de acceso en la clase
derivada. Notese que no se requiere ( o permite ) una declaracion de tipo en una declaracion
de acceso.
para ver como una declaracion de acceso funciona, comenzemos con este corto fragmento:
class base {
public:
int j; // public en base
};

// heredar base como private
class derivada : private base {
public:

// aqui esta la declaracion de acceso
base::j; // hacer j publica nuevamente.
// ...
};
Como base es heredada como private por derivada, la variable publica j es hecha una variable
'private' en derivada. Sin embargo, la inclusion de esta declaracion de acceso
base::j;
Puede usar una declaracion de acceso para restaturar los derechos de acceso de miembros
'public' y 'protected', Sin embargo, no puede usar una declaracion de acceso para elevar o
disminuir un estado de acceso de un miembro. Por ejemplo, un miembro declarado como
private dentro de una clase base no puede ser hecho public por una clase derivada. ( Permitir
esto destruirira la encapsulacion!)
El siguiente programa ilustra el uso en declaraciones de acceso.

#include <iostream>
using namespace std;

class base {
int i; // private en base

public:
int j, k;
void seti(int x) { i = x; }
int geti() { return i; }
};

// Heredar base como private
class derivada : private base {

public:
/* las siguientes tres declaraciones
sobreescriben la herencia de base
como private y restablece j, seti()
y geti() a publico acceso
*/
base::j; // hacer j public nuevamente - pero no k
base::seti; // hacer seti() public
base::geti; // hacer geti() public

// base::i; // ilegal - no se puede elevar el acceso

int a; // public
};

int main()
{

derivada obj;

// obj.i = 10; // ilegal porque i es private en derivada

obj.j = 20; // legal porque j es hecho public en derivada
//obj.k = 30; // ilegal porque k es private en derivada

obj.a = 40; // legal porque a es public en derivada
obj.seti(10);

cout << obj.geti() << " " << obj.j << " " << obj.a;

return 0;
}

Notese como este programa usa declaraciones de acceso para restaurar j, seti(), y geti() a un
estadi 'public'. Los comentarios describen otras varias restricciones de acceso.
C++ provee la habilidad de ajustar acceso a los miembros heredados para acomodar aquellas
situaciones especiales en las cuales la mayoria de una clase heredad esta pensada para ser
private, pero unos cuantos miembros se hacen para mantener su estado public o protected. Es
mejor usar esta caracteristica escasamente.
LEYENDO GRAFICOS DE HERENCIA EN c++[editar]
En ocasiones las jerarquias de clases en C++ son hechas graficamente para hacerlas mas
facil de comprender. Sin embargo, debido a la forma en que estas son usualmente dibujadas
por programadores de C++, los graficos de herencia son a veces incomprendidos por
principiantes. Por ejemplo, considere una situacion en la cual la clase A es heredad por la
clase B, la cual es heredada por la clase C. Usando la notacion estandar C++, esta situacion
es dibujada como se muestra aqui:
NOTA: "el simbolo ^ es la punta de la fecha,
que indica direccion."
A
^
|
B
^
|
C
Como puede ver, las flechas apuntan hacia arriba, no hacia abajo. Mientras que muchas
personas encuentran inicialmente la direccion de las flechas contra-intuitivasm este es el estilo
que la mayoria de los programadores de C++ han adoptado. En graficos al estilo C++, las
flechas apuntan a la clase base. Ademas, la flecha quiere decir "derivada desde", y no
"derivando". Aqui tenemos otro ejemplo. Puede describir en palabras que significa esto?
A B
^ ^
| |
^ ^
C D
^ ^
\ /
\ /
\ /
E
Este grafico declara que la clase E es derivada de C y D. ( Eso es, E tiene multiples clases
base, llamadas C y D.) Ademas, C es derivada de A, y D derivada de B.
Mientras que la direccion de las flechas puede confundir a la primera, es mejor que se sienta
familiar con este estilo de notacion grafica, ya que es comunmente usada en libros, revistas, y
documentacion de compiladores.
CLASES BASE VIRTUALES[editar]
Un elemento de ambiguedad puede ser introducido en un programa C++ cuando multiples
clases bases son heredadas. Considere este incorrecto programa:
// Este programa contiene un error y no compilara.
#include <iostream>
using namespace std;

class base {
public:
int i;
};

// derivada 1 hereda base
class derivada1 : public base {

public:
int j;
};

// derivada2 hereda base
class derivada2 : public base {

public:
int k;
};

/* derivada3 hereda de ambas, derivada1 y derivada2
esto significa que hay 2 copias de base en derivada3!
*/

class derivada3 : public derivada1, public derivada2 {
public:

int sum;
};

int main()
{

derivada3 obj;

obj.i = 10; // esto es ambiguo; cual i???
obj.j = 20;
obj.k = 30;

// i es ambiguo aqui, tambien
obj.sum = obj.i + obj.j + obj.k;

// tambien ambiguo, cual i?
cout << obj.i << " ";

cout << obj.j << " " << obj.k << " ";
cout << obj.sum;

return 0;
}

Como indican los comentarios en este programa, ambos derivada1 y derivada2 heredan base.
Sin embargo, derivada3 hereda ambos, derivada1 y derivada2. Como resultado existen dos
copias de base presenten en un objeto del tipo derivada3, asi pues una expresion como

obj.i = 20;
hacia cual i se esta haciendo referencia? La que se encuentra en derivada1 o derivada2?
Como existen dos copias de base presentes en el objeto 'obj' entonces hays dos obj.i's. Como
puede ver, la declaracion es inherentemente ambigua.

Existen dos maneras de remediar el anterior programa. La primera es aplicar el operador de
resolucion de ambito para manualmente seleccionar una 'i'. Por ejemplo, la siguiente version el
programa compilara y se ejecutara como se esperaba:

// Este programa usa el la resolucion de
// ambito explicita para seleccionar 'i'
#include <iostream>
using namespace std;

class base {
public:
int i;
};

// derivada 1 hereda base
class derivada1 : public base {

public:
int j;
};

// derivada2 hereda base
class derivada2 : public base {

public:
int k;
};

/* derivada3 hereda de ambas, derivada1 y derivada2
esto significa que hay 2 copias de base en derivada3!
*/

class derivada3 : public derivada1, public derivada2 {
public:

int sum;
};

int main()
{

derivada3 obj;

obj.derivada1::i = 10; // ambito resuelto, se usa la 'i' derivada1
obj.j = 20;
obj.k = 30;

// ambito resuelto
obj.sum = obj.derivada1::i + obj.j + obj.k;

// tambien resuelto aqui..
cout << obj.derivada1::i << " ";

cout << obj.j << " " << obj.k << " ";
cout << obj.sum;

return 0;
}
Aplicando ::, el programa manualmente selecciona a derivada1 como version de base. Sin
embargo, esta solucion levanta un detalle profundo: Que pasa si solo una copia de base es en
realidad requerida? Existe alguna forma de prevenir que dos copias sean incluidas en
derivada3? La respuesta, como probablemente ha adivinado se logra con 'clases base
virtuales'.
Cuando dos o mas objetos son derivados de una clase base comun, puede prevenir multiples
copias de la clase base de estar presentes en un objeto derivado por esas clases, declarando
la clase base como virtual cuando esta es heredada. para hacer esto, se precede el nombre
de la clase base con la palabra virtual cuando esta es heredada.
Para ilustrar este proceso, aqui esta otra version del programa de ejemplo. Esta vez,
derivada3 contiene solo una copia de base.

// Este programa usa clases base virtuales.
#include <iostream>
using namespace std;

class base {

public:
int i;
};

// derivada1 hereda base como virtual
class derivada1 : virtual public base {

public:
int j;
};

// derivada2 hereda base como virtual
class derivada2 : virtual public base {
public:
int k;
};

/* derivada3 hereda ambas, derivada1 y derivada2.
Esta vez, solo existe una copia de la clase base.
*/

class derivada3 : public derivada1, public derivada2 {
public:
int sum;
};

int main()
{

derivada3 obj;

obj.i = 10; // ahora no-ambiguo
obj.j = 20;
obj.k = 30;

// no-ambiguo
obj.sum = obj.i + obj.j + obj.k;

// no-ambiguo
cout << obj.i << " ";

cout << obj.j << " " << obj.k << " ";
cout << obj.sum;

return 0;
}

Como puede ver la palabra clave 'virtual' precede el resto de la especificacion de la clase
heredada. Ahora que ambas, derivada1 y derivada2 han heredado base como virtual,
cualquier herencia multiple que las incluya causara que solo una copia de base se encuentre
presente. Ademas, en derivada3 existe solo una copia de base, y obj.i = 10 es perfectamente
valida y no-ambiguo.
Otro punto a tener en mente: incluso cuando ambas, derivada1 y derivada2 espcifican base
como virtual, base sigue presente en los dos tipos derivados. Por ejemplo, la siguiente
secuencia es perfectamente valida:

// Definir una clase del tipo derivada1

derivada1 miclase;

miclase.i = 88;

La diferencia entre una clase base normal y una virtual se hace evidente solo cuando un
objeto hereda la base clase mas de una vez, si la clase base ha sido declarada como virtual,
entonces solo una instancia de esta estara presente en el objeto heredado. De otra manera,
multiples copias serian encontradas.
Funciones virtuales
Programacin en C++/Funciones virtuales
Editores:

Herencia Punteros
Contenido
[ocultar]
1 Introduccin
2 PUNTEROS A TIPOS DERIVADOS.
o 2.1 REFERENCIAS A TIPOS DERIVADOS
o 2.2 FUNCIONES VIRTUALES
o 2.3 LAS FUNCIONES VIRTUALES SON HEREDADAS
o 2.4 PORQUE FUNCIONES VIRTUALES
o 2.5 UNA SIMPLE APLICACION DE LAS FUNCIONES VIRTUALES
o 2.6 FUNCIONES VIRTUALES PURAS Y CLASES ABSTRACTAS
o 2.7 ENLACE TEMPRANO VS TARDIO
o 2.8 POLIMORFISMO Y EL PURISTA
Introduccin[editar]
Una de las tres mayores facetas de la programacin orientada a objetos es el polimorfismo.
Aplicado a C++, el trmino polimorfismo describe el proceso por el cual diferentes
implementaciones de una funcin pueden ser accedidas a travs del mismo nombre. Por esta
razn, el polimorfismo es en ocasiones caracterizado por la frase "Un interfaz, mltiples
mtodos". Esto significa que cada miembro de una clase general de operaciones puede ser
accedido del mismo modo, incluso cuando las acciones especficas con cada operacin
puedan diferir.
En C++, el polimorfismo es soportado en tiempo de ejecucin y en tiempo de compilacin. La
sobrecarga de operadores y funciones son ejemplos de polimorfismo en tiempo de
compilacin. Aunque la sobrecarga de operadores y funciones es muy poderosa, stos no
pueden realizar todas las tareas requeridas por un lenguaje realmente orientado a objetos.
Adems, C++ tambin permite polimorfismo en tiempo de ejecucin a travs del uso de clases
derivadas y funciones virtuales, que son los principales temas de este captulo.
Este captulo comienza con una corta discusin de punteros a tipos derivados, ya que stos
dan soporte al polimorfismo en tiempo de ejecucin.
PUNTEROS A TIPOS DERIVADOS.[editar]
La fundacion del polimorfismo en tiempo de ejecucion es el puntero de la clase base. Punteros
a la clase base y clases derivadas estan relacionados en la manera en que otros tipos de
puntero no lo estan. Como aprendio al principio del libro, un puntero de un tipo generalmente
no puede apuntar a un objeto de otro tipo. Sin embargo, los punteros de clase base y objetos
derivados son la excepcion a esta regla. En C++, un puntero de la clase base podria ser usado
para apuntar a un objeto de cualquier clase derivada de esa base. Por ejemplo, asumiendo
que usted tiene una clase base llamada 'clase_B' y una clase llamada 'clase_D', la cual es
derivada de 'clase_B'. En C++, cualquier puntero declarado como un puntero a 'clase_B'
puede tambien ser un puntero a 'clase_D'. Entonces, dado
clase_B *p; // puntero al objeto del tipo clase_B
clase_B objB // objeto del tipo clase_B
clase_D objD // objeto del tipo clase_D
las siguientes dos declaraciones son perfectamente validas:

p = &objB; // p apunta a un objeto del tipo clase_B
p = &objD /* p apunta a un objeto del tipo clase_D
el cual es un objeto derivado de clase_B. */

En este ejemplo, 'p' puede ser usado para acceder a todos los elementos de objD heredados
de objB. Sin embargo elementos especificos a objD no pueden ser referenciados con 'p'.
Para un ejemplo mas concreto, considere el siguiente programa, el cual define una clase
llamada clase_B y una clase derivada llamada clase_D. Este programa usa una simple
jerarquia para almacenar autores y titulos.
// Usando punteros base en objetos de una clase derivada
#include <iostream>
#include <cstring>
using namespace std;

class clase_B {
public:
void put_autor(char *s) { strcpy(autor, s); }
void mostrar_autor() { cout << autor << "\n"; }
private:
char autor[80];
};

class clase_D : public clase_B {
public:
void put_titulo(char *num) { strcpy(titulo, num); }
void mostrar_titulo() {
cout << "Titulo: ";
cout << titulo << "\n";
}
private:
char titulo[80];
};

int main()
{
clase_B *p;
clase_B objB;

clase_D *dp;
clase_D objD;

p = &objB; // direccion la clase base

// Accesar clase_B via puntero
p->put_autor("Tom Clancy");

// Accesar clase_D via puntero base
p = &objD;
p->put_autor("William Shakespeare");

// Mostrar cada autor a traves de su propio objeto.
objB.mostrar_autor();
objD.mostrar_autor();
cout << "\n";

/* Como put_titulo() y mostrar_titulo() no son parte
de la clase base, ellos no son accesibles a traves
del puntero base 'p' y deben ser accedidas
directamente, o, como se muestra aqui, a traves de
un puntero al tipo derivado.
*/

*dp = objD;
dp->put_titulo("La Tempestad");
p->mostrar_autor(); // los dos, 'p' o 'dp' pueden ser usados aqui.
dp->mostrar_titulo();

return 0;
}
Este programa muestra lo siguiente:
Tom Clancy
William Shakespeare

William Shakespeare
Titulo: La Tempestad

En este ejemplo, el puntero 'p' es definido como un puntero a clase_B. Sin embargo, este
puede apuntar a un objeto de la clase derivada clase_D y puede ser usado para acceder
aquellos elementos de la clase derivada que son heredados de la clase base. Pero recuerde,
un puntero base no puede acceder aquellos elementos especificos de la clase derivada. De
ahi el porque de que mostrar_titulo() es accesada con el puntero dp, el cual es un puntero a la
clase derivada.
Si se quiere acceder a los elementos definidos en una clase derivada usando un puntero de
clase base, se debe hacer un casting hacia el puntero del tipo derivado. Por ejemplo, esta
linea de codigo llamara apropiadamente a la funcion mostrar_titulo() en objD:
((clase_D *)p)->mostrar_titulo();

Los parentesis externos son necesarios para asociar el cast con 'p y no con el tipo de retorno
de mostrar_titulo(). Aunque no hay nada tecnicamente erroneo con castear un puntero de esta
manera, es probablemente mejor evitarlo, ya que este simplemente agrega confusion a sus
codigo. ( En realidad, la mayoria de los programadores de C++ consideran esto como mala
forma.)
Otro punto a comprender es que, mientras un puntero base puede ser usado para apuntar a
cualquier objeto derivado, no es posible hacerlo de manera inversa. Esto es, no puede
acceder a un objeto de tipo base usando un puntero a una clase derivada.
Un puntero es incrementado y decrementado relativamente a su tipo base. Por lo tanto,
cuando un puntero de la clase base esta apuntado a un objeto derivado, incrementarlo o
decrementarlo no hara que apunte al siguiente objeto de la clase derivada. En vez de eso,
apuntara a ( lo que piense que es ) el proximo objeto de la clase base. Por lo tanto, deberia
considerar invalido incrementar o decrementar un puntero de clase base cuando esta
apuntando a un objeto derivado.
El hecho de que un puntero a un tipo base pueda ser usado para apuntar a cualquier objeto
derivado de la base es extremadamente importante, y fundamental para C++. Como
aprendera muy pronto, esta flexibilidad es crucial para la manera en que C++ implementa su
polimorfismo en tiempo de ejecucion.
REFERENCIAS A TIPOS DERIVADOS[editar]
Similar a la accin de punteros ya descritas, una referencia a la clase base puede ser usada
para referirse a un objeto de un tipo derivado. La mas comun aplicacion de esto es encontrada
en los parametros de la funciones. Un parametro de referencia de la clase base puede recibir
objetos de la clase base asi como tambien otro tipo derivado de esa misma base.
FUNCIONES VIRTUALES[editar]
El polimorfismo en tiempo de ejecucion es logrado por una combinacion de dos
caracteristicas: 'Herencia y funciones virtuales". Aprendio sobre la herencia en el capitulo
precedente. Aqui, aprendera sobre funcion virtual.
Una funcin virtual es una funcion que es declarada como 'virtual' en una clase base y es
redefinida en una o mas clases derivadas. Ademas, cada clase derivada puede tener su
propia version de la funcion virtual. Lo que hace interesantes a las funciones virtuales es que
sucede cuando una es llamada a traves de un puntero de clase base ( o referencia ). En esta
situacion, C++ determina a cual version de la funcion llamar basandose en el tipo de objeto
apuntado por el puntero. Y, esta determinacion es hecha en 'tiempo de ejecucion'. Ademas,
cuando diferentes objetos son apuntados, diferentes versiones de la funcion virtual son
ejecutadas. En otras palabras es el tipo de objeto al que esta siendo apuntado ( no el tipo del
puntero ) lo que determina cual version de la funcion virtual sera ejecutada. Ademas, si la
clase base contiene una funcion virtual, y si dos o mas diferentes clases son derivadas de esa
clase base, entonces cuando tipos diferentes de objetos estan siendo apuntados a traves de
un puntero de clase base, diferentes versiones de la funcion virtual son ejecutadas. Lo mismo
ocurre cuando se usa una refrencia a la clase base.
Se declara una funcion como virtual dentro de la clase base precediendo su declaracion con la
palabra clave virtual. Cuando una funcion virtual es redefinida por una clase derivada, la
palabra clave 'virtual' no necesita ser repetida ( aunque no es un error hacerlo ).
Una clase que incluya una funcion virtual es llamada una 'clase polimorfica'. Este termino
tambien aplica a una clase que hereda una clase base conteniendo una funcion virtual.
Examine este corto programa, el cual demuestra el uso de funciones virtuales:

// Un ejemplo corto que usa funciones virtuales.
#include <iostream>
using namespace std;

class base {
public:
virtual void quien() {cout << "Base" << endl;} // especificar una
clase virtual
};

class primera_d : public base {
public:
// redefinir quien() relativa a primera_d
void quien() {cout << "Primera derivacion" << endl;}
};

class segunda_d : public base {
public:
// redefinir quien relativa a segunda_d
void quien() {cout << "Segunda derivacion" << endl;}
};

int main()
{
base obj_base;
base *p;

primera_d obj_primera;
segunda_d obj_segundo;

p = &obj_base;
p->quien(); // acceder a quien() en base

p = &obj_primera;
p->quien(); // acceder a quien() en primera_d

p = &obj_segundo;
p->quien(); // acceder a quien() en segunda_d

return 0;
}

Este programa produce la siguiente salida:
Base
Primera derivacion
Segunda derivacion
Examinemos el programa en detalle para comprender como funciona:
En 'base', la funcion 'quien()' es declarada como 'virtual'. Esto significa que la funcion puede
ser redefinida en una clase derivada. Dentro de ambas 'primera_d' y 'segunda_d', 'quien()' es
redefinida relativa a cada clase. Dentro de main(), cuatro variables son declaradas: 'obj_base',
el cual es un objeto del tipo 'base'; 'p' el cual un un puntero a objetos del tipo 'base';
'obj_primera' y 'obj_segunda', que son objetos de dos clases derivadas. A continuacion 'p' es
asignada con la direccion de 'obj_base', y la funcion quien() es llamada. Como quien() es
declarada como virtual, C++ determina en tiempo de ejecucion, cual version de quien() es
referenciada por el tipo del objeto apuntado por 'p'. En este caso, 'p' apunta a un objeto del
tipo 'base', asi que es la version de 'quien()' declarada en 'base' la que es ejecutada. A
continuacion, se le asigna a 'p' la direccion de 'obj_primera'. Recuerde que un puntero de la
clase base puede referirse a un objeto de cualquier clase derivadas. Ahora, cuando quien() es
llamada, C++ nuevamente comprueba para ver que tipo de objeto es apuntado por 'p' y
basado en su tipo, determina cual version de quien() llamar. Como 'p' apunta a un objeto del
tipo 'obj_primera', esa version de quien() es usada. De ese mismo modo, cuando 'p' es
asignada con la direccion de 'obj_segunda', la version de quien() declarada en 'segunda_d' es
ejecutada.

RECUERDE: "Es determinado en tiempo de ejecucion cual version de una funcion virtual en
realidad es llamada. Ademas, esta determinacion es basada solamente en el tipo del objeto
que esta siendo apuntado por un puntero de clase base."
Una funcion virtual puede ser llamada normalmente, con la sintaxis del operador estandar de
'objeto.' Esto quiere decir que en el ejemplo precedente, no seria incorrecto sintacticamente
acceder a quien() usando esta declaracion:
obj_primera.quien();
Sin embargo, llamar a una funcion virtual de esta manera ignora sus atributos polimorficos. Es
solo cuando una funcion virtual es accesada por un puntero de clase base que el polimorfismo
en tiempo de ejecucion es logrado.
A primera vista, la redefinicion de una funcion virtual en una clase derivada parece ser una
forma especial de sobrecarga de funcion. Sin embargo, este no es el caso. De hecho, los dos
procesos son fundamentalmente diferentes. Primero, una funcion sobrecargada debe diferir en
su tipo y/o numero de parametros, mientras que una funcion virtual redefinida debe tener
exactamente el mismo tipo y numero de parametros. De hecho, los prototipos para una
funcion virtual y sus redefiniciones debe ser exactamente los mismos. Si los prototipos
difieren, entonces la funcion simplemente se considera sobrecargada, y su naturaleza virtual
se pierde. Otra restriccion es que una funcion virtual debe ser un miembro, no una funcion
'friend', de la clase para la cual es definida. Sin embargo, una funcion virtual puede ser una
funcion 'friend' de otra clase. Tambien, es permisible para funciones destructores ser virtuales,
pero esto no es asi para los constructores.
"Cuando una funcion
virtual es
redefinida en una
clase derivada,
se dice que es
una funcion
'overriden' ( redefinida )"

Por las restricciones y diferencias entre sobrecargar funciones normales y redefinir funciones
virtuales, el termino 'overriding' es usado para describir la redefinicion de una funcion virtual.
LAS FUNCIONES VIRTUALES SON HEREDADAS[editar]
Una vez que una funcion es declarada como virtual, esta se mantiene virtual sin importar
cuantas capas de clases derivadas esta debe perdurar. Por ejemplo, si 'segunda_d' es
derivada de 'primera_d' en vez de 'base', como se muestra en el proximo ejemplo, entonces
quien() es aun virtual y la version apropiada es aun correctamente seleccionada.
// Derivar de primera_d, no de base.
class segunda_d : public primera_d {
public:
void quien() { // definir 'quien()' relativa a 'segunda_d'
cout << "Segunda derivacion\n";
}
};
Cuando una clase derivada no redefine una funcion virtual, entonces la funcion, como se
definicio en la clase base, es usada. Por ejemplo intente esta version del programa precedente
en el cual 'segunda_d' no redefine 'quien()':
#include <iostream>
using namespace std;

class base {
public:
virtual void quien() {
cout << "Base\n";
}
};

class primera_d : public base {
public:
void quien() {
cout << "Primera derivacion\n";
}
};

class segunda_d : public base {
public:
// quien() no definida
};

int main()
{
base obj_base;
base *p;

primera_d obj_primera;
segunda_d obj_segunda;

p = &obj_base;
p->quien(); // acceder a quien() en 'base'

p = &obj_primera;
p->quien(); // acceder a quien() en 'primera_d'

p = &obj_segunda;
p->quien(); /* acceder a quien() en 'base'
porque segunda_d no la redefine */

return 0;
}

El programa ahora muestra la salida siguiente:
Base
Primera derivacion
Base
Como confirma la salida, como 'quien()' no ha sido redefinida por 'segunda_d', entonces 'p'
apunta a 'obj_segunda', es la version de 'quien()' en 'base' la que es ejecutada.
Mantenga en mente que las caracteristicas heredadas de 'virtual' son jeraquicas. Por tanto,, si
el ejemplo precendente es modificado para que 'segunda_d' sea derivada de 'primera_d' en
vez de 'base', entonces cuando quien() es referenciada relativa a un objeto del tipo
'segunda_d', es la version de 'quien()' declarada dentro de primera_d' la que es llamada ya
que es la clase mas cercana a 'segunda_d', no 'quien()' dentro de base. El siguiente programa
demuestra esta jerarquia.
#include <iostream>
using namespace std;

class base {
public:
virtual void quien() {
cout << "Base\n";
}
};

class primera_d : public base {
public:
void quien() {
cout << "Primera derivacion\n";
}
};

// segunda_d ahora hereda primera_d -- no base.
class segunda_d : public primera_d {
// quien() no es definida.
};

int main()
{
base obj_base;
base *p;

primera_d obj_primera;
segunda_d obj_segunda;

p = &obj_base;
p->quien(); // acceder a 'quien()' en 'base'.

p = &obj_primera;
p->quien(); // acceder a 'quien()' en 'primera'.

p = &obj_segunda;
p->quien(); /* acceder a 'quien()' en 'primera_d'
porque 'segunda_d' no la redefine */

return 0;
}

Este programa produce la siguiente salida:
Base
Primera derivacion
Primera derivacion
Como puede ver, 'segunda_d' ahora usa la version 'quien()' de 'primera_d' porque esa version
es la mas cercana en la cadena de herencia.
PORQUE FUNCIONES VIRTUALES[editar]
Como se declaraba en el inicio de este captulo, las funciones virtuales en combinacin con
tipos derivados le permiten a C++ soportar polimorfismo en tiempo de ejecucin. El
polimorfismo es esencial para la programacin orientada a objetos por una razn: Esta permite
a una clase generalizada especificar aquellas funciones que sern comunes a todas las
derivadas de esa clase, mientras que permite a una clase derivada definir la implementacin
especfica de algunos o todas de esas funciones. A veces esta idea es expresada como: La
clase base dicta la 'interface' general que cualquier objeto derivado de esa clase tendr, pero
permite a la clase derivada definir el mtodo actual usado para implementar esa interface. De
ah que la frase "una interface mltiples mtodos" sea usada a menudo para describir el
polimorfismo.
Parte del truco de aplicar el polimorfismo de una manera satisfactoria es comprender que la
clase base y derivada forman una jerarqua, la cual se mueve de mayor a menor
generalizacin (base a derivada). Diseada correctamente, la clase base provee todos los
elementos que una clase derivada puede usar directamente. Tambin define cuales funciones
la clase derivada debe implementar por su cuenta. Esto permite a la clase derivada la
flexibilidad para definir sus propios mtodos, y aun mantener un interface consistente. Eso es,
como la forma de la interface es definida por la clase base, cualquier clase derivada
compartir esa interface comn. Adems, el uso de funciones virtuales hace posible para la
clase base definir interfaces genricas que sern usada por todas las clases derivadas. En
este punto, usted debe preguntarse a si mismo porque una consistente interface con mltiples
implementaciones es importante. La respuesta, nuevamente, no lleva a la fuerza central
manejadora detrs de la programacin orientada a objetos: Esta ayuda al programador a
manejar programas de complejidad creciente. Por ejemplo, si usted desarrolla su programa
correctamente, entonces usted sabr que todos los objetos que usted derive de una clase
base son accedidos en la misma manera general, incluso si las acciones especficas varan de
una clase derivada a la prxima. Esto significa que usted necesita solo recordar una interface,
en vez de varias. Tambin, su clase derivada es libre de usar cualquiera o toda la
funcionalidad provista por la clase base. No necesita reinventa esos elementos. Por tanto, la
separacin de interface e implementacin permite la creacin de libreras de clases, las cuales
pueden ser provistas por un tercero. Si estas libreras son implementadas correctamente, ellas
proveern una interface comn que usted puede usar para derivar clases suyas propias que
cumplan sus necesidades especificas. Por ejemplo, tanto como las Microsoft Fundation
Classes ( MFC ) y la librera de clases .NET Framework Windows Forms soporta
programacin en Windows. Usando estas clases, su programa puede heredar mucha de la
funcionalidad requerida por un programa de Windows. Usted necesita agregar solo las
caractersticas nicas a su aplicacin. Este es un mayor beneficio cuando se programa en
sistemas complejos.
UNA SIMPLE APLICACION DE LAS FUNCIONES VIRTUALES[editar]
Para tener una idea del poder del concepto "una interface, multiples metodos", examinemos el
siguiente programa. Este crea una clase base llamada 'figura'. Esta clase almacena las
dimensiones de varios objetos de 2-dimensiones y calcula sus areas. La funcion 'set_dim()' es
una funcion miembro estandar porque esta operacion sera comun a las clases derivadas. Sin
embargo, 'mostrar_area()' es declarada como virtual porque el metodo de computar el area de
cada objeto puede variar. El programa usa 'figura' para derivar dos clases especificas
llamadas 'rectangulo' y 'triangulo'.
#include <iostream>
using namespace std;

class figura {
protected:
double x, y;
public:
void set_dim(double i, double j) {
x = i;
y = j;
}

virtual void mostrar_area() {
cout << "No hay calculo de area definido ";
cout << " para esta clase.\n";
}
};

class triangulo : public figura {

public:
void mostrar_area() {
cout << "Triangulo con alto ";
cout << x << " y base " << y;
cout << " tiene un area de ";
cout << x * 0.5 * y << ".\n";
}
};

class rectangulo : public figura {

public:
void mostrar_area() {
cout << "Rectangulo con dimensiones ";
cout << x << " x " << y;
cout << " tiene un area de ";
cout << x * y << ".\n";
}
};

int main()
{
figura *p; // crear un puntero al tipo base.

triangulo t; // crear objetos de tipos derivados
rectangulo r;

p = &t;
p->set_dim(10.0, 5.0);
p->mostrar_area();

p = &r;
p->set_dim(10.0, 5.0);
p->mostrar_area();

return 0;
}

La salida es mostrada aqui:
Triangulo con alto 10 y base 5 tiene un area de 25.
Rectangulo con dimensiones 10 x 5 tiene un area de 50.
En el programa, notese que ambas interfaces, 'rectangulo' y 'triangulo', son la misma, incluso
ambas proveen sus propios metodos para computar el area de cada uno de sus objetos.
Dada la declaracion para 'figura', es posible derivar una clase llamada 'circulo' que computara
el area de un circulo, dado en radio? La respuesta es 'Si'. Todo lo que necesita hacer es crear
un nuevo tipo derivado que calcule el area de un circulo. El poder de las funciones virtuales
esta basado en el hecho de que usted puede facilmente derivar un nuevo tipo que mantendra
un interface comun con otros objetos relaciones. Por ejemplo, esta es una manera de hacerlo:

class circulo : public figura {
public:
void mostrar_area() {
cout << "Circulo con radio ";
cout << x;
cout << " tiene un area de ";
cout << 3.14 * x * x;
}
};
Antes de intentar usar 'circulo', vea de cerca la definicion de 'mostrar_area()'. Note que esta
usa solo el valor de x, el cual se asume que almacena el radio. ( Recuerde, el area de un
circulo es calculada usando la formula 'PI*R a la 2'.) Sin embargo, la funcion 'set_dim()' como
se define en 'figura', asume que seran pasados dos valores, no solo uno. Como 'circulo' no
requiere este segundo valor, que tipo de accin podemos tomar?
Hay dos manera de resolver este problema. La primera y peor, usted simplemente llama a
'set_dim()' usando un valor falso como segundo parametro cuando use un objeto 'circulo'. Esto
tiene la desventaja de ser chapucero, en conjunto requiriendo que recuerde una excepcion
especial, la cual viola la filosofia "una interface, muchos metodos".
Una mejor manera de resolver este problema es pasarle al parametro 'y' dentro de 'set_dim()'
un valor por defecto. Entonces, cuando se llame a 'set_dim()' para un circulo, necesita
especificar solo el radio. Cuando llame a 'set_dim()' para un triangulo o un rectangulo,
especificara ambos valores. El programa expandido, el cual usa este metodo, es mostrado
aqui:

#include <iostream>
using namespace std;

class figura {
protected:
double x, y;
public:
void set_dim(double i, double j=0) {
x = i;
y = j;
}

virtual void mostrar_area() {
cout << "No hay calculo de area definido ";
cout << " para esta clase.\n";
}
};

class triangulo : public figura {

public:
void mostrar_area() {
cout << "Triangulo con alto ";
cout << x << " y base " << y;
cout << " tiene un area de ";
cout << x * 0.5 * y << ".\n";
}
};

class rectangulo : public figura {

public:
void mostrar_area() {
cout << "Rectangulo con dimensiones ";
cout << x << " x " << y;
cout << " tiene un area de ";
cout << x * y << ".\n";
};
};

class circulo : public figura {
public:
void mostrar_area() {
cout << "Circulo con radio ";
cout << x;
cout << " tiene un area de ";
cout << 3.14 * x * x;
}
};


int main()
{
figura *p; // crear un puntero al tipo base

triangulo t; // crear objetos de tipos derivada
rectangulo r;
circulo c;

p = &t;
p->set_dim(10.0, 5.0);
p->mostrar_area();

p = &r;
p->set_dim(10.0, 5.0);
p->mostrar_area();

p = &c;
p->set_dim(9.0);
p->mostrar_area();

return 0;
}
Este programa produce la siguiente salida:
Triangulo con alto 10 y base 5 tiene un area de 25.
Rectangulo con dimensiones 10 x 5 tiene un area de 50.
Circulo con radio 9 tiene un area de 254.34
TIP: Mientras que las funciones virtuales son sintacticamente faciles de comprender, su
verdadero poder no puede ser demostrado en ejemplos cortos. En general, el polimorfismo
logra su gran fuerza en sistemas largos y complejos. Si continua usando C++, las
oportunidades de aplicar funciones virtuales se presentaran por si mismas.
FUNCIONES VIRTUALES PURAS Y CLASES ABSTRACTAS[editar]
Como se ha visto, cuando una funcion virtual que no es redefinida en una clase derivada es
llamada por un objeto de esa clase derivada, la version de la funcion como se ha definido en la
clase base es utilizada. Sin embargo, en muchas circunstancias, no habra una declaracion con
significado en una funcion virtual dentro de la clase base. Por ejemplo, en la clase base 'figura'
usada en el ejemplo anterior, la definicion de 'mostrar_area()' es simplemente un sustituto
sintetico. No computara ni mostrara el area de ningun tipo de objeto. Como vera cuando cree
sus propias librerias de clases no es poco comun para una funcion virtual tener una definicion
sin significado en el contexto de su clase base.
Cuando esta situacion ocurre, hay dos manera en que puede manejarla. Una manera, como
se muestra en el ejemplo, es simplemente hacer que la funcion reporte un mensaje de
advertencia. Aunque esto puede ser util en ocasiones, no es el apropiado en muchas
circunstancias. Por ejemplo, puede haber funciones virtuales que simplemente deben ser
definidas por la clase derivada para que la clase derivada tenga algun significado. Considere
la clase 'triangulo'. Esta no tendria significado si 'mostrar_area()' no se encuentra definida. En
este caso, usted desea algun metodo para asegurarse de que una clase derivada, de hecho,
defina todas las funciones necesarias. En C++, la solucion a este problema es la 'funcion
virtual pura.'
Una 'funcion virtual pura' es una funcin declarada en una clase base que no tiene definicion
relativa a la base. Como resultado, cualquier tipo derivado debe definir su propia version --
esta simplemente no puede usar la version definida en la base. Para declarar una funcion
virtual pura use esta forma general:
virtual 'tipo' 'nombre_de_funcion'(lista_de_parametros) = 0;

Aqui, 'tipo' es el tipo de retorno de la funcion y 'nombre_de_funcion' es el nombre de la
funcion. Es el = 0 que designa la funcion virtual como pura. Por ejemplo, la siguiente version
de 'figura', 'mostrar_area()' es una funcion virtual pura.

class figura {
double x, y;
public:
void set_dim(double i, double j=0) {
x = i;
y = j;
}

virtual void mostrar_area() = 0; // pura
};
Declarando una funcion virtual como pura, se fuerza a cualquier clase derivada a definir su
propia implementacin. Si una clase falla en hacerlo, el compilador reportara un error. Por
ejemplo, intente compilar esta version modificando del programa de figuras, en el cual la
definicin de mostrar_area() ha sido removida de la clase 'circulo':
/*
Este programa no compilara porque la clase
circulo no redefinio mostrar_area()
*/

#include <iostream>
using namespace std;

class figura {
protected:
double x, y;
public:
void set_dim(double i, double j=0) {
x = i;
y = j;
}

virtual void mostrar_area() = 0; // pura

};

class triangulo : public figura {

public:
void mostrar_area() {
cout << "Triangulo con alto ";
cout << x << " y base " << y;
cout << " tiene un area de ";
cout << x * 0.5 * y << ".\n";
}
};

class rectangulo : public figura {

public:
void mostrar_area() {
cout << "Rectangulo con dimensiones ";
cout << x << " x " << y;
cout << " tiene un area de ";
cout << x * y << ".\n";
};
};

class circulo : public figura {
// la no definicion de mostrar_area() causara un error
};


int main()
{
figura *p; // crear un puntero al tipo base

triangulo t; // crear objetos de tipos derivada
rectangulo r;
circulo c; // ilegal -- no puedo crearla!

p = &t;
p->set_dim(10.0, 5.0);
p->mostrar_area();

p = &r;
p->set_dim(10.0, 5.0);
p->mostrar_area();


return 0;
}
Si una clase tiene al menos una funcion virtual pura, entonces esa clase se dice que es
'abstracta'. Una clase abstracta tiene una caracteristica importante: No puede haber objetos de
esa clase. En vez de eso, una clase abstracta debe ser usada solo como una base que otras
clases heredaran. La razon por la cual una clase abstracta no puede ser usada para declarar
un objeto es, por supuesto, que una o mas de sus funciones no tienen definicion. Sin
embargo, incluso si la clase base es abstracta, la puede usar aun para declarar punteros o
referencias, los cuales son necesarios para soportar el polimorfismo en tiempo de ejecucion.
ENLACE TEMPRANO VS TARDIO[editar]
Existen dos terminos que son comunmente usado cuando se discute sobre programacin
orientada a objetos: "Enlace temprano y Enlace Tardio" ( del ingles "early binding and late
binding" ). Relativo a C++, estos terminos se refieren a eventos que ocurren en tiempo de
compilacion y eventos que ocurren en tiempo de ejecucion, respectivamente.
Enlace temprano significa que una llamada a una funcion es resuelta en tiempo de
compilacion. Esto es, toda la informacion necesaria para llamar a una funcion es conocida
cuando el programa es compilado. Ejemplos de enlace temprano incluyen llamadas a
funciones estandar, llamadas a funciones sobrecargadas y llamadas a funciones de
operadores sobrecargados. La principal ventaja del enlace temprano es la eficiencia -- es
rapido, y a menudo requiere menos memoria. Su desventaja es falta de flexibilidad.
Enlace tardio significa que una llamada a la funcion es resuelta en tiempo de ejecucin. Mas
precisamente a que la llamada a la funcion es determinada "al vuelo" mientras el programa se
ejecuta. Enlace tardio es logrado en C++ a traves del uso de funciones virtuales y tipos
derivados. La ventaja del enlace tardio es que permite gran flexibilidad. Puede ser usada para
soportar una interface comn, mientras que se permite a varios objetos utilizar esa interface
para definir sus propias implementaciones. Por tanto, puede ser usada para ayudar a crear
librerias de clases, las cuales pueden ser reusadas y extendidas. Su desventaja, sin embargo,
es una ligera perdida de velocidad de ejecucion.
POLIMORFISMO Y EL PURISTA[editar]
A traves de este libro, y en este capitulo especificamente, se ha hecho una distincion entre
polimorfismo de tiempo de ejecucion y en tiempo de compilacion. Caracteristicas polimorficas
en tiempo de compilacion son sobrecarga de operadores y funciones. El polimorfismo en
tiempo de ejecucion es logrado con funciones virtuales. La definicion mas comun de
polimorfismo es, "una interface, multiples metodos", y todas estas caracteristicas se ajustan a
este significado. Sin embargo, aun existe controversia con el uso del termino "polimorfismo".
Algunos puristas POO han insistido que el termino debe usarse para referise solo a eventos
que ocurren en tiempo de ejecucin. Tambin, ellos podrian decir que solo las funciones
virtuales soportan el polimorfismo. Parte de este punto de vista esta fundado en el hecho de
que los primeros lenguajes de computacin polimrficos fueran intrpretes (en el que todos los
eventos ocurrian en tiempo de ejecucin). La llegada de lenguajes polimrficos compilador
expandi el concepto de polimorfismo. Sin embargo, aun algunos aseguran que el trmino
polimorfismo debera referirse solo a eventos en tiempo de ejecucin. La mayora de los
programadores de C++ no estan de acuerdo con este punto de vista y establecen que el
trmino aplica en ambos casos a caractersticas en tiempo de compilacin y en tiempo de
ejecucin. Sin embargo, no se sorprenda si algun dia, alguien va en contra de usted sobre el
uso de este termino!
Si su programa usa enlace tardio o temprano depende de lo que el programa este diseado
para hacer. ( En realidad, la mayoria los programas grandes usan una combinacion de los
dos.) Enlace tardio es una de las caractersticas mas poderosas de c++. Sin embargo, el
precio que usted paga por este poder es que su programa se ejecutara ligeramente mas lento.
Por lo tanto, es mejor usar enlace tardio solo cuando este le agregue significado a la
estructura y manejabilidad de su programa. ( En esencia, use -- pero no abuse -- el poder.)
Mantenga en mente, sin embargo, que la perdida de desempeo causada por enlace tardio es
muy ligera, asi pues cuando la situacin requiera enlace tardio, usted definitivamente deberia
usarlo.
Punteros
Programacin en C++/Punteros
Editores:
Funciones virtuales Estructuras II
Contenido
[ocultar]
1 Punteros
o 1.1 Sintaxis
o 1.2 Operadores
o 1.3 Punteros y matrices
o 1.4 Aritmtica de Punteros
o 1.5 Matrices de punteros
o 1.6 Formas de pasar un valor por referencia
o 1.7 Punteros a funciones
o 1.8 Ordenamiento burbuja
o 1.9 Proyecto de colas para un banco
Punteros[editar]
Los punteros permiten simular el paso por referencia, crear y manipular estructuras dinamicas
de datos, tales como listas encadenadas, pilas, colas y rboles. Generalmente las variables
contienen valores especificos. Los punteros son variables pero en vez de contener un valor
especifico, contienen las direcciones de las variables a las que apuntan. Para obtener o
modificar el valor de la variable a la que apuntan se utiliza el operador de indireccin. Los
punteros, al ser variables deben ser declaradas como punteros antes de ser utilizadas.
Sintaxis[editar]
int *ptrID, ID;
ID = 8;
ptrID = &ID; // puntero a ID
ptrID es un puntero a int, mientras que la variable ID es solo una variable del tipo int. Todo
puntero debe ser precedido por un asterisco (*)en la declaracin.
Se puede declarar ms de un puntero en la misma sentencia. En el ejemplo que sigue se ve la
declaracin de dos punteros a int.
int *ptrY, *ptrX;
Operadores[editar]
Existen dos operadores a tener en cuenta cuando trabajamos con punteros. El operador de
direccin (&) que devuelve la direccin de memoria de su operando y el operador de
indireccin (*) que devuelve un alias para el objeto al cual apunta el operando del puntero.
En el siguiente ejemplo vemos como se inicializa una variable X con el valor 15. Luego se crea
un puntero a int y por ltimo el puntero pasa a apuntar a la variable X. Esto es, ptrX es un
puntero a X.
int X = 15;
int *ptrX;
ptrX = &X;
Punteros y matrices[editar]
Las matrices son punteros constantes. Una matriz sin subindice es un puntero al primer
elemento de la matriz.
int X[15];
int *ptrX;
ptrX = &X; // ptrX recibe la direccin del primer elemento ( 0 ) de X
As como tambin podra escribirse
int X[15];
int *ptrX;
ptrX = &X[0]; // ptrX es igual a la direccin del primer elemento de X
Se pueden utilizar distintos elementos de la matriz teniendo en cuenta la sintaxis de punteros.
int X[15], Y, *ptrX;
ptrX = X;

Y = *( ptrX + 7 );
En este caso puede verse que Y toma el valor del elemento 7 de la matriz X, siendo 7 el
desplazamiento dentro de la matriz. El operador de indireccin queda fuera del parntesis
porque tiene una prioridad superior a la del operador +. De no existir los parntesis, se
sumaria 7 al elemento X[0]. Teniendo en cuenta que las matrices son punteros constantes, el
nombre de la matriz puede tratarse como un puntero:
Y = *( X + 7 );
Aritmtica de Punteros[editar]
Al usar punteros a matrices, hay que tener en cuenta que la aritmtica cambia sensiblemente.
#include <iostream>

using std::cout;
using std::endl;

void main()
{
int X[6] = { 1, 2, 3, 4, 5, 6 };
int *prtX;

prtX = X; // incializo el valor del puntero.

cout << endl << *prtX;
prtX += 2;
cout << endl << *prtX;
prtX -= 2;
cout << endl << *prtX;
prtX++;
cout << endl << *prtX;
}

atte: Oscar Torres & David Paz
En el siguiente cdigo, primero se crea un puntero a un arreglo de 6 elementos y si inicializa el
puntero prtX al primer elemento del arreglo X[0]. Si tenemos en cuenta que el siguiente
ejemplo se ejecuta en una computadora con enteros de 4 bytes, el segundo elemento de la
matriz tendr en memoria un desplazamiento de 4 bytes, el 2 de ocho y asi sucesivamente. La
operacin prtX += 2; produce un desplazamiento llevndolo al 3 elemento dentro del arreglo.
Debe entenderse que prtX ahora apunta a una direccin de memoria y la instruccin cambia
esta direccin de memoria sumndole 2 multiplicado por el tamao del tipo de dato del arreglo
que en este supuesto sera de 4. (dir = ( dir + 2 * 4 )), dando por resultado un desplazamiento
de 8 bytes. Sera igual que ejecutar la operacin prtX = &X[2];. La operacin prtX -= 2 obedece
a la misma lgica estableciendo el puntero al primer elemento del array X[0] y el operador ++
modifica el puntero desplazndolo 4 bytes y asignndole el segundo elemento de la matriz.
Matrices de punteros[editar]
Para realizar una estructura de datos dinmica, se puede utilizar una matriz donde sus
elementos sean punteros. Suponiendo que queramos hacer un calendario y lo dividamos por
semanas. Podramos utilizar una matriz con los das de la semana.
const char *dias[7] = { "Domingo", "Lunes", "Martes", "Miercoles",
"Jueves", "Viernes", "Sabado" }
Cada da de la semana, no es un elemento de la matriz, sino que la expresin dias[7] crea una
matriz de siete elementos como punteros a char.
Formas de pasar un valor por referencia[editar]
Un puntero constante a un dato no constante
#include <iostream>
void sumoeldoble( int * ); // prototipo

void main ()
{
int X = 15;
sumoeldoble( &X ); // Pasa la direccin de memoria de X .
std::cout << X;

}

void sumoeldoble( int *ptrX )
{
// Toma el valor de X mediante el operador de indireccin
// La funcion no devuelve nada porque modifica el valor por
referencia.
*ptrX = *ptrX + ( *ptrX * 2 );
}
Un puntero no constante a un dato constante
#include <iostream>

void imprimeChars( const char * ); // prototipo

void main ()
{
char cFrase[] = "Hola Mundo";
imprimeChars( cFrase );
}

void imprimeChars( const char *ptrStr )
{
for ( ; *ptrStr != '\0'; ptrStr++ ) //Sin inicializacin
std::cout << *ptrStr;
}
Un puntero constante a un dato no constante
Un puntero es constante cuando apunta siempre a la misma direccin de memoria y si el dato
no es constante entonces el valor puede ser modificado.
void main ()
{
int foo, bar;
int * const ptrFoo = &foo; // Apuntador constante a un entero en
la direccin de memoria de foo

*ptrFoo = 53;


// Esto devuelve un error porque es un puntero constante.
// No se puede alterar la direccin de memoria a la que apunta.
ptrFoo = &bar;
}
Un puntero constante a un dato constante
El puntero constante apunta siempre a la misma direccin de memoria y el valor al que apunta
dicho puntero no puede ser modificado mediante el puntero. Este es el metodo en que se
debe pasar matrices a funciones que solo leen la matriz y no la modifican.
#include <iostream>

using namespace std;

int main ()
{
int foo = 3, bar;
const int * const ptrFoo = &foo;

cout << foo;

*ptrFoo = 53; //Error porque no puede alterarse el valor
ptrFoo = &bar; // Error

foo = 23;

cout << foo;

}
Punteros a funciones[editar]
Teniendo en cuenta que el nombre de una funcin es en verdad la direccin de memoria
donde comienza el cdigo, los punteros a funciones contienen la direccin de memoria de la
funcin a la que apunta, y se pueden pasar y retornar entre funciones.
#include <iostream>
using namespace std;

bool functionA( int, int, bool (*)( int ) ); //Prototipo
bool functionB( int ); //Prototipo

void main()
{
int x = 113, y = 226;
if ( functionA( x, y, functionB ) )
cout << "\nEl resultado es verdadero";
else
cout << "\nEl resultado es falso";
}

bool functionA( int param1, int param2, bool (*verificar)( int ) )
{
if ( ( (*verificar)( param1 ) ) && ( (*verificar)( param2 ) )
)
return true;
}

bool functionB( int param )
{
if ( param > 100 )
return true;
else
return false;
}
En el ejemplo anterior podr ver que en la definicin de los prototipos, la funcin functionA
recibe tres parmetros, siendo el tercer parmetro un puntero a la funcion functionB,
practicamente copiando el prototipo sin el nombre. Cuando se ejecuta functionA, se le pasa
como parametro el nombre de la funcin
Ordenamiento burbuja[editar]
Ordenamiento burbuja utilizando punteros
#include <iostream>
#include <iomanip>

using namespace std;

void orden( int *, const int ); // prototipo
void swap( int * const, int * const ); // prototipo

int main()
{
const int nSize = 10;
int a[ nSize ] = { 3, 9, 14, 27, 18, 154, 8, 6, 74, 33 };

cout << "\nElementos a ordenar\n";

for ( int j = 0; j < nSize; j++ )
cout << setw( 5 ) << a[ j ];

orden( a, nSize ); // ordena el arreglo

cout << "\nElementos ordenados\n";

for ( int j = 0; j < nSize; j++ )
cout << setw( 5 ) << a[ j ];

cout << endl;

return 0; // indica terminacin exitosa

}

void orden( int *matriz, const int nSize )
{
for ( int pasada = 0; pasada < nSize - 1; pasada++ )
{
for ( int k = 0; k < nSize - 1; k++ )
{
if ( matriz[ k ] > matriz[ k + 1 ] )
{
swap( &matriz[ k ], &matriz[ k + 1 ] );
}
}
}
}

void swap( int * const ptrElemento1, int * const ptrElemento2 )
{
int mantiene = *ptrElemento1;
*ptrElemento1 = *ptrElemento2;
*ptrElemento2 = mantiene;
}
Proyecto de colas para un banco[editar]
Por cada 2 clientes normales pasa uno VIP al Cajero

El codigo es muy simple pero muy trabajado y depurado, esta relizado con if/while.... lo mas
complicado son los apuntadores, pero nada del otro mundo, muestra el perfecto uso de
funciones, tiene una clave: jahvi, de todas lo puedes leer en el codigo. Compila perfecto en
DEV C++. Tiene una interfaces muy creativa, ideal estudian tes que se estan inciando en el
desarrollo de software con programacion estructurada. recuerda copiarlo en un pagina en
blanco en dev c++ desde aqui: (copialo completo y compilalo)
#include <stdio.h>
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

using namespace std;

typedef struct nodo
{
int cedula;
struct nodo*siguiente;
}tiponodo;

typedef tiponodo *pnodo;
typedef tiponodo *cola;

cola cola_n=NULL;
cola cola_vip=NULL;
int solic;

void insertar (cola *cola_n)
{
cola aux, creado;

creado=(pnodo)malloc(sizeof(tiponodo));

cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;
cout<<" ||||||||||||||||||||METROPOLI banco
universal||||||||||||||||||||"<<endl;
cout<<" |||||||||||||||||||||||Le da la
bienvenida|||||||||||||||||||||||"<<endl;
cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;
cout<<" Estimado cliente: Introduzca su numero de cedula"<<endl;
cin>> creado->cedula;
cout<<" Pronto sera atendido"<<endl;


if ((*cola_n)==NULL)
{
creado->siguiente=*cola_n;
*cola_n=creado;
}
else
{
aux=*cola_n;

while(aux!=NULL)
{
if(aux->siguiente==NULL)
{
creado->siguiente=aux->siguiente;
aux->siguiente=creado;
aux=aux->siguiente;
}
aux=aux->siguiente;
}
}
}

void mostrar_cola (cola cola_n)
{
cola aux;
aux=cola_n;
if(aux==NULL)
{
cout<<"No hay clientes en cola"<<endl;
}
else
{
while(aux!=NULL)
{
cout<<"Cedula: "<<aux->cedula<<endl;
cout<<""<<endl;
aux=aux->siguiente;
cout<<"* Clientes ordenados por orden de
llegada((((((SIMCOLAS))))))"<<endl;
}
}
}
//modificado hasta ac... falta de orden por parte del creador
void insertar_vip (cola *cola_vip){
cola aux_2, creado_vip;
creado_vip=(pnodo)malloc(sizeof(tiponodo));
cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;//62
cout<<" ||||||||||||||||||||METROPOLI banco
universal||||||||||||||||||||"<<endl;
cout<<" |||||||||||||||||||||||Le da la
bienvenida|||||||||||||||||||||||"<<endl;
cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;
cout<<" Estimado cliente: Introduzca su numero de
cedula"<<endl;
cin>> creado_vip->cedula;
cout<<" Pronto sera atendido"<<endl;
if ((*cola_vip)==NULL){
creado_vip->siguiente=*cola_vip;
*cola_vip=creado_vip;
}else{
aux_2=*cola_vip;
while(aux_2!=NULL){
if(aux_2->siguiente==NULL){
creado_vip->siguiente=aux_2->siguiente;
aux_2->siguiente=creado_vip;
aux_2=aux_2->siguiente;
}
aux_2=aux_2->siguiente;
}
}
}

void mostrar_cola_vip (cola cola_vip){
cola aux_2;
aux_2=cola_vip;
if(aux_2==NULL){
cout<<"No hay clientes V.I.P en cola"<<endl;
}else{
while(aux_2!=NULL){
cout<<"Cedula: "<<aux_2->cedula<<endl;
cout<<""<<endl;
cout<<"* Clientes ordenados por orden de
llegada((((((SIMCOLAS))))))"<<endl;
aux_2=aux_2->siguiente;
}
}
}

void pop (cola *cola_n){

if((*cola_n)==NULL){
cout<<"No hay clientes en cola ((((((SIMCOLAS))))))"<<endl;
cout<<""<<endl;
}

if((*cola_n)!=NULL){
cout<<"Cliente: "<<(*cola_n)->cedula;
cout<<" es su turno"<<endl;
*cola_n=(*cola_n)->siguiente;
free(cola_n);
system("PAUSE");
cout<<""<<endl;
}

if((*cola_n)==NULL){
cout<<"No hay clientes en cola ((((((SIMCOLAS))))))"<<endl;
cout<<""<<endl;
}else{

cout<<"Cliente: "<<(*cola_n)->cedula;
cout<<" es su turno"<<endl;
*cola_n=(*cola_n)->siguiente;
free(cola_n);
system("PAUSE");
cout<<""<<endl;
}
}

void pop_vip(cola *cola_vip){

if(cola_vip!=NULL){
cout<<"Cliente: "<<(*cola_vip)->cedula;
cout<<" es su turno"<<endl;
*cola_vip=(*cola_vip)->siguiente;
free(cola_vip);
}else{
cout<<"No hay usuarios V.I.P en cola
((((((SIMCOLAS))))))"<<endl;
}
}



void menu();
void Insertar();
void insertar_vip();
void mostrar_cola();
void mostrar_colavip();
void solicitar_numero();
void salir();


struct perly{
char uxer[];
}data;

struct perly *p = &data;


int main(int argc, char *argv[])
{

system("color 0a");

cout<<" * *
* "<<endl;
cout<<" * *
"<<endl;
cout<<" * | * * *
* "<<endl;
cout<<" * -+- *
"<<endl;
cout<<" __ | * * *
* "<<endl;
cout<<" ___| | * _|_ * ____ ____
"<<endl;
cout<<" [_]||__ _| |_ * | |....| |....| *
* "<<endl;
cout<<" | | _|[] []|_ ___ | |....| | ___|__
"<<endl;
cout<<" [_]| |__|_ ______| | | |_| |....| || -- - |
* * "<<endl;
cout<<" |________ |__ | |# #| |_| |....| || - -- |
_____ "<<endl;
cout<<" [_]| _____ | |__[]| | | |_| |....|__|| -- - |
|* * *| "<<endl;
cout<<" | [___] | |__ |# #| |_| |....|__|| -- -
_|_|* * *| "<<endl;
cout<<" [_]| | | | |__| |__|....| || ___|*
*|* * *| "<<endl;
cout<<" | _____ | |__ #|_______|....| | |* *|*
*|* * *| "<<endl;
cout<<" [_]| [___] | |__|_______|__ | | |* *|*
*|* * *| "<<endl;
cout<<" | | __|_____________|__ |* *|*
*|* * *| "<<endl;
cout<<" [_]| _____ | _|___________________|_ |* *|*
*|* * *| "<<endl;
cout<<" | [___] | |_______________________|
______________ "<<endl;
cout<<" __|_______|_________|_______________________|
_________________ "<<endl;
cout<<"
|_______________________________________________________________|"<<en
dl;
cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;//62
cout<<" ||||||||||||||||||||METROPOLI banco
universal||||||||||||||||||||"<<endl;
cout<<" ||||||||||||Sistema Integral para el Manejo de
COLAS|||||||||||||"<<endl;
cout<<"
|||||||||||||||||||||||||||||SIMCOLAS||||||||||||||||||||||||||||"<<en
dl;
cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;
cout<<" |||||||||Creado por: Javier Rodriguez Caracas-
Venezuela||||||||||"<<endl;
cout<<"
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<en
dl;
cout<<" Login: ";
char usuario[6] = "jahvi";
cin.getline(p->uxer,6);

if (strcmp(p->uxer,usuario) == 0) {
cout<<"Bienvenid@ al sistema "<<endl;
menu();
cout<<""<<endl;
}else{
cout<<"Acceso Denegado. Consulte
al Admisnistrador "<<endl;
}

system("PAUSE");
return EXIT_SUCCESS;
}
void menu() {
short a;
do {

cout<<""<<endl;
cout<< "0 - Agregar Cliente"<<endl;
cout<< "1 - Agregar Cliente V.I.P"<<endl;
cout<< "2 - Solicitar Numero"<<endl;
cout<< "3 - Mostrar Cola"<<endl;
cout<< "4 - Mostrar Cola V.I.P"<<endl;
cout<< "5 - Salir del Sistema"<<endl;
cout<<""<<endl;

fflush(stdout);

cout<<"Opcion #:";
cin>>a;
cout<<""<<endl;

if (a == 5)
exit(1);

switch(a){
case 0 :
Insertar();
break;

case 1 :
insertar_vip();
break;

case 2 :
solicitar_numero();
break;

case 3 :
mostrar_cola();
break;

case 4 :
mostrar_colavip();
break;

case 5 :
salir();
break;

default :
puts("Usted no ha seleccionado nada, porfavor seleccione
algo\n");
break;
};
} while (1);
}

void Insertar(){
insertar(&cola_n);
}
void insertar_vip(){
insertar(&cola_vip);
}

void mostrar_cola(){
mostrar_cola(cola_n);
}

void mostrar_colavip(){
mostrar_cola_vip(cola_vip);
}

void solicitar_numero(){
pop(&cola_n);

if(cola_vip!=NULL){
pop_vip(&cola_vip);
}else{
cout<<"No hay cliente V.I.P en cola
((((((SIMCOLAS))))))"<<endl;
}

}

void salir(){
}
Estructuras II
Programacin en C++/Estructuras II
Editores:
Oscar E. Palacios
Punteros Plantillas
Contenido
[ocultar]
1 Introduccin
o 1.1 Pilas o Stacks
1.1.1 Pila en arreglo esttico
1.1.2 Pila dinmica
o 1.2 Colas o Queues
1.2.1 Cola en un arreglo esttico
o 1.3 Colas de doble enlace
Introduccin[editar]
Muchos autores comienzan por definir los conceptos de estructura de datos a raiz de
estructuras conocidas como listas. En el mismo contexto, suele suceder que a dichas listas
tambin se les conoce como secuencias y/o colecciones de datos. Hay que decir que dichos
autores estn (en parte) en lo correcto, ya que una lista (de cualquier tipo) es una estructura
ideada con el propsito de albergar datos agrupados bajo un mismo nombre. Al respecto,
podemos pensar que las listas son como arreglos de datos, es decir, para hacer una
introduccin al manejo y programacin de listas encadenadas podemos tomar como punto
de partida a los arreglos estticos. Es as como en esta secccin se descubrir la forma de
operacin de tres tipos comnes de listas conocidas como: PILAS, COLAS Y DOBLE
COLA (STACK, QUEUE, DQUEUE). En programacin, el uso de listas es una prctica tan
extendida que lenguajes tales como (por ejemplo) Java, Python y C++ soportan los
mecanismos necesarios para trabajar con estructuras de: Vectores, Pilas, Colas, Listas, etc.
En C++, los programadores que usen Dev-Cpp ( Bloodshed.software -Dev-C++ ) pueden
aprovechar las ventajas que ofrecen las STL (Standard Templates Libraries) dentro de la cual
se pueden encontrar plantillas para la manipulacin de listas tales como: Vectores, Listas,
Sets, Maps, etc. Por otro lado, los usuarios de Borland C++ ( Turbo C++ version 1.01 ) pueden
hacer uso de la CLASSLIB, misma que posee las librerias para los propsitos mencionados.

Nota: En las siguientes secciones se presentarn seis programas, tres para simular listas
basadas en arreglos estticos y tres para simular listas por medio de enlaces dinmicos
(punteros). En cuanto al material incluido se debe hacer las siguientes declaraciones:
1. Puesto que el material es puramente didctico, cada programa se escribe en un
mismo archivo. La idea es no perder de vista el objetivo. Los entendidos sabrn que
normalmente se deben escribir archivos de cabecera, archivos de implementacion y
archivos de prueba por separado.
2. Para cada una de las clases creadas en los programas se han elegido nombres en
ingles. La idea es que gran parte de la documentacin e implementacin referente a
listas est en dicho idioma, as, se le da al estudiante la idea bsica de como operar
con las libreras soportadas por los compiladores Dev-Cpp, Borlan C++, y otros.
3. Igual, se debe observar que los mtodos de las clases tienen nombres en ingles, y que
con el objetivo de establecer cierta estandarizacin todas las clases poseen los
mismos mtodos, aunque cada una de ellas implementa los mismos a su manera.
Pilas o Stacks[editar]
Una PILA es una estructuras en donde cada elemento es insertado y
retirado
del tope de la misma, y debido a esto el comportamiento de un una pila
se
conoce como LIFO (ltimo en entrar, primero en salir ).
Un ejemplo de pila o stack se puede observar en el mismo procesador, es decir, cada vez que
en los programas aparece una llamada a una funcin el microprocesador guarda el estado de
ciertos registros en un segmento de memoria conocido como Stack Segment, mismos que
sern recuperados al regreso de la funcin.
Pila en arreglo esttico[editar]
En el programa que se ver en seguida, se simula el comportamiento de una estructura de
pila. Aunque en el mismo se usa un arreglo esttico de tamao fijo se debe mencionar que
normalmente las implementaciones hechas por fabricantes y/o terceras personas se basan en
listas dinmicas o enlazadas.
Para la implementacin de la clase Stack se han elegido los mtodos:
put(), poner un elemento en la pila
get(), retirar un elemento de la pila
empty(), regresa 1 (TRUE) si la pila esta vacia
size(), nmero de elementos en la pila
El atributo SP de la clase Stack es el puntero de lectura/escritura, es
decir, el SP
indica la posicin dentro de la pila en donde la funcin put() insertar
el siguiente
dato, y la posicin dentro de la pila de donde la funcin get() leer el
siguiente dato.
Cada vez que put() inserta un elemento el SP se decrementa.
Cada vez que get() retira un elemento el SP se incrementa.

En el siguente ejemplo se analiza lo que sucede con el SP (puntero de pila) cuando se
guardan en la pila uno por uno los caracteres 'A', 'B', 'C' y 'D'. Observe que al principio el SP
es igual al tamao de la pila.

Llenando la pila.
SP
|
+---+---+---+---+---+
| | | | | | al principio (lista vacia)
+---+---+---+---+---+
SP
|
+---+---+---+---+---+ push('A');
| | | | | A | despus de haber agregado el primer elemento
+---+---+---+---+---+
...
SP
|
+---+---+---+---+---+
| | D | C | B | A | despus de haber agregado cuatro elementos
+---+---+---+---+---+

Vaciando la pila.
SP
|
+---+---+---+---+---+ pop();
| | D | C | B | A | despus de haber retirado un elemento
+---+---+---+---+---+
...
SP
|
+---+---+---+---+---+
| | D | C | B | A | despus de haber retirado todos los elementos
+---+---+---+---+---+
Nota: observe que al final la lista est vacia, y que dicho estado se
debe a que
el puntero est al final de la pila y no al hecho de borrar fsicamente
cada elemento
de la pila.

Ejemplo: Pila basada en un arreglo esttico
#include <iostream>
using namespace std;

#define STACK_SIZE 256 /* capacidad mxima */
typedef char arreglo[STACK_SIZE];

class Stack {

int sp; /* puntero de lectura/escritura */
int items; /* nmero de elementos en lista */
int itemsize; /* tamao del elemento */
arreglo pila; /* el arreglo */

public:
// constructor
Stack() {
sp = STACK_SIZE-1;
items = 0;
itemsize = 1;
}

// destructor
~Stack() {};

/* regresa el nmero de elementos en lista */
int size() { return items; }

/* regresa 1 si no hay elementos en la lista, o sea, si la
lista est vacia */
int empty() { return items == 0; }

/* insertar elemento a la lista */
int put(char d)
{
if ( sp >= 0) {
pila[sp] = d;
sp --;
items ++;
}
return d;
}

/* retirar elemento de la lista */
int get()
{
if ( ! empty() ) {
sp ++;
items --;
}
return pila[sp];
}

}; // fin de clase Stack


// probando la pila.
// Nota: obseve cmo los elementos se ingresan en orden desde la A
hasta la Z,
// y como los mismos se recupern en orden inverso.
int main()
{
int d;
Stack s; // s es un objeto (instancia) de la clase Stack

// llenando la pila
for (d='A'; d<='Z'; d++) s.put(d);

cout << "Items =" << s.size() << endl;

// vaciando la pila
while ( s.size() ) cout << (char)s.get() << " ";

cout << "\nPara terminar oprima <Enter>...";
cin.get();
return 0;
}
}

Pila dinmica[editar]
En el siguiente programa se presenta una implementacin de una estructura dinmica tipo pila
o stack. Es importante hacer notar que, a diferencia de una pila basada en un arreglo esttico,
una pila enlazadada dinmicamente no posee de forma natural el mecanismo de acceso por
ndices, en ese sentido, el programador puede crear los algoritmos necesarios para permitir tal
comportamiento. En la clase que presentaremos en el ejemplo no se ha implementado el
mecanismo de acceso por ndices, ya que la misma se presenta como una alternativa para la
simulacin de una pila o stack.
Uno de los puntos ms destacables en cuando al uso de listas enlazadas dinmicamente es el
hecho de crear estructuras conocidas como nodos. Un nodo es una especie de eslabn (
similar al de una cadena de bicicleta ), es decir, cada nodo se enlaza con otro a travs de un
puntero que apunta a una estructura del mismo tipo que el nodo. Por ejemplo, para crear una
estructura de nodo para almacenar enteros y a la vez para apuntar a otro posible nodo
podemos emplear la sintaxis:
struct nodo {
int data;
nodo *siguiente;
};
observe que con la declaracin anterior estamos creando el tipo estructurado nodo, mismo
que posee a los miembros: data para guardar valores enteros, y siguiente para apuntar o
enlazar a un supuesto siguiente nodo.
Ya que las listas dinmicas inicialmente se encuentran vacias, y ms an, una lista dinmica
no posee una direccin establecida en tiempo de compilacin ya que las direccin de memoria
que ocupar cada uno de los elementos se establecer en tiempo de ejecucin, entonces
cmo determinar la condicin de vacio ?. En nuestro ejemplo usaremos un contador ( ITEMS )
que dicho sea de paso, si ITEMS = 0, entonces la lista est vacia. ( la condicin de vacio
tambin podra determinarse al verificar el SP, es decir, si el SP = NULL, significa que la lista
no posee elementos ).
Al hacer un anlisis previo de los eventos que acontecern en la pila y su puntero de lectura y
escritura (SP, que en esta ocasin es una estructura tipo nodo), se tiene lo siguiente:
1) Al principio la lista est vacia, en ese caso el SP es igual a NULL y, en
consecuencia, el puntero next tambin es NULL.
SP = NULL

+------+------+
| ???? | next |--> NULL
+------+------+
2) Despus de agregar el primer elemento la situacin se vera as:
SP = asignado
1
+------+------+
| data | next |--> NULL
+------+------+
3) Despus de agregar otro elemento la situacin se vera as:
SP = asignado
2 1
+------+------+ +------+------+
| data | next |--> | data | next |--> NULL
+------+------+ +------+------+
Ejemplo: Pila basada en un arreglo dinmico
/*----------------------------------------------------------
-----+
+ ejemplo de una pila ( STACK ) enlazada dinmicamente +
+ +
+ Autor: Oscar E. Palacios +
+ email: oscarpalacios1@yahoo.com.mx +
+ +
+ Manifiesto: +
+ Este programa puede distribuirse, copiarse y modificarse
de +
+ forma libre. +
+-----------------------------------------------------------
----*/
#include <iostream>
//#include <conio.h>

using namespace std;

/* tipo de dato que contendr la lista */
typedef char DATA_TYPE;

// declaracin de estructura nodo
struct nodo {
DATA_TYPE data;
nodo *next;
};

class StackDin {

// atributos
int ITEMS; /* nmero de elementos en la lista */
int ITEMSIZE; /* tamao de cada elemento */
nodo *SP; /* puntero de lectura/escritura */

public:
// constructor
StackDin() : SP(NULL), ITEMS(0),
ITEMSIZE(sizeof(DATA_TYPE)) {}

// destructor
~StackDin() {}

/* agregar componente a la lista */
DATA_TYPE put(DATA_TYPE valor)
{
nodo *temp;

temp = new nodo;
if (temp == NULL) return -1;

temp->data = valor;
temp->next = SP;
SP = temp;
ITEMS ++;
return valor;
}

int empty() { return ITEMS == 0; }


/* retirar elemento de la lista */
DATA_TYPE get()
{
nodo *temp;
DATA_TYPE d;

if ( empty() ) return -1;

d = SP->data;
temp = SP->next;
if (SP) delete SP;
SP = temp;
ITEMS --;
return d;
}

}; // fin de la clase StackDin


/* punto de prueba para la clase StackDin */
int main()
{
//clrscr();

StackDin s;
DATA_TYPE d;

for (d='A'; d<='Z'; d++) s.put(d);

while ( ! s.empty() )
cout << (DATA_TYPE)s.get() << " ";

cout << "\nPara terminar presione <Enter>...";
cin.get();
return 0;
}
Colas o Queues[editar]
Una cola sencilla es una estructura en donde cada elemento es
insertado
inmediatamente despus del ltimo elemento insertado; y donde
los elementos
se retiran siempre por el frente de la misma, debido a esto el
comportamiento
de un una cola se conoce como FIFO (primero en entrar, primero
en salir).
Un ejemplo a citar de cola es el comportamiento del buffer del teclado.
Cuando en el teclado se oprime una tecla, el cdigo del carcter ingresado es
trasladado y depositado en una rea de memoria intermedia conocida como "el
buffer del teclado", para esto el microprocedador llama a una rutina especfica.
Luego, para leer el carcter depositado en el buffer existe otra funcin, es decir,
hay una rutina para escribir y otra para leer los caracteres del buffer cada una de
las cuales posee un puntero; uno para saber en donde dentro del buffer se
escribir el siguiente cdigo y otro para saber de donde dentro del buffer se leer
el siguiente cdigo.
Cola en un arreglo esttico[editar]
En el programa que se ve en seguida, se simula el comportamiento de una
estructura de cola simple. Aunque en el mismo se usa un arreglo esttico de
tamaoo fijo se debe mencionar que normalmente las implementaciones hechas
por fabricantes y/o terceras personas se basan en listas dinmicas o
dinamicamente enlazadas.
Para la implementacin de la clase Queue se han elegido los mtodos:
put(), poner un elemento en la cola
get(), retirar un elemento de la cola
empty(), regresa 1 (TRUE) si la cola est vacia
size(), nmero de elementos en la cola
El atributo cabeza de la clase Queue es el puntero de
lectura.
El atributo cola de la clase Queue es el puntero de
escritura.
Es decir, la cola indica la posicin dentro de la lista en donde la funcin put()
insertar el siguiente dato, y la cabeza indica la posicin dentro de la lista de
donde la funcin get() leer el siguiente dato.
Cada vez que put() inserta un elemento la cola se incrementa.
Cada vez que get() retira un elemento la cabeza se incrementa.
En el siguente ejemplo se analiza lo que sucede con la cola y la cabeza (punteros
de escritura y de lectura de la Lista) cuando se guardan en la cola uno por uno los
caracteres 'A', 'B', 'C' y 'D'. Observe que al principio: cola = cabeza = cero.

Llenando la cola.
cola
|
+---+---+---+---+---+
| | | | | | al principio
+---+---+---+---+---+
|
cabeza
cola
|
+---+---+---+---+---+ put('A');
| A | | | | | despus de haber agregado el primer
elemento
+---+---+---+---+---+
|
cabeza
...
cola
|
+---+---+---+---+---+
| A | B | C | D | | despus de haber agregado cuatro
elementos
+---+---+---+---+---+
|
cabeza
Vaciando la cola.
cabeza
|
+---+---+---+---+---+
| A | B | C | D | | antes de haber retirado elementos
+---+---+---+---+---+
cabeza
|
+---+---+---+---+---+ get();
| A | B | C | D | | despus de haber retirado un elemento
+---+---+---+---+---+
...
cabeza
|
+---+---+---+---+---+ al final
| A | B | C | D | | despus de haber retirado todos los
elementos
+---+---+---+---+---+
|
cola
Observese que al final el cabeza apunta hacia el mismo elemento que la cola, es
decir, la cola vuelve a estar vacia. Puesto que la cola que estamos proyectando
reside en un arreglo esttico los componentes del arreglo an estn dentro de la
misma, salvo que para su recuperacin se debera escribir otro mtodo. En una
cola dinmica (como se demostrar ms adelante) los elementos retirados de la
misma se eliminan de la memoria y podra no ser posible su recuperacin
posterior.
Nota: En el programa que aparece en seguida, al tipo de lista implementado por
la clase Queue se le conoce como "lista circular" debido al comportamiento de sus
punteros. Es decir si los mtodos para escribir o leer detectan que el puntero
correspondiente ha sobrepasado el tamao mximo de elementos permitidos
dentro de la cola, ste es puesto a cero.
Ejemplo: cola en un arreglo esttico
/*----------------------------------------------------------
-----+
+ ejemplo de una cola (QUEUE) basada en un arreglo esttico
+
+ +
+ Autor: Oscar E. Palacios +
+ email: oscarpalacios1@yahoo.com.mx +
+ +
+ Manifiesto: +
+ Este programa puede distribuirse, copiarse y modificarse
de +
+ forma libre. +
+-----------------------------------------------------------
----*/
#include <iostream.h>

#define MAX_SIZE 256 /* capacidad mxima */
typedef char almacen[MAX_SIZE];

class Queue {

int cabeza; /* puntero de lectura */
int cola; /* puntero de escritura */
int ITEMS; /* nmero de elementos en la lista */
int ITEMSIZE; /* tamao de cada elemento */
almacen alma; /* el almacen */

public:
// constructor
Queue() {
cabeza = 0;
cola = 0;
ITEMS = 0;
ITEMSIZE = 1;
}

// destructor
~Queue() {}

// regresa 1 (true) si la lista est vacia
int empty() { return ITEMS == 0; }

// insertar elemento a la lista
int put(int d)
{
if ( ITEMS == MAX_SIZE) return -1;
if ( cola >= MAX_SIZE) { cola = 0; }
alma[cola] = d;
cola ++;
ITEMS ++;
return d;
}

// retirar elemento de la lista
int get()
{
char d;
if ( empty() ) return -1;
if ( cabeza >= MAX_SIZE ) { cabeza = 0; }
d = alma[cabeza];
cabeza ++;
ITEMS --;
return d;
}

// regresa el nmero de elementos en lista
int size() { return ITEMS; }

}; // fin de la clase Queue


// probando la cola
int main()
{
int d;
Queue q;

for (d='A'; d<='Z'; d++) q.put(d);

cout << "Items = " << q.size() << endl;

while ( q.size() ) {
cout << (char)q.get() << " ";
}

cout << "\nPara terminar oprima <Enter> ...";
cin .get();
return 0;
}
Ejemplo: cola en un arreglo dinmico
/*----------------------------------------------------------
-----+
+ ejemplo de una cola (QUEUE) basada en un arreglo dinmico
+
+ +
+ Autor: Oscar E. Palacios +
+ email: oscarpalacios1@yahoo.com.mx +
+ +
+ Manifiesto: +
+ Este programa puede distribuirse, copiarse y modificarse
de +
+ forma libre. +
+-----------------------------------------------------------
----*/
#include <iostream>

using namespace std;

typedef char DATA_TYPE;

struct nodo {
DATA_TYPE data;
nodo *next;
};

class QueueDin {

// atributos
int ITEMS, ITEMSIZE;
nodo *cola, *cabeza;

public:
// constructor
QueueDin() : cola(NULL), cabeza(NULL), ITEMS(0),
ITEMSIZE(sizeof(DATA_TYPE)) {}

// destructor
~QueueDin() {}

/* agregar componente a la lista */
DATA_TYPE put(DATA_TYPE valor)
{
nodo *temp;

temp = new nodo;
if (temp == NULL) return -1;

ITEMS ++;
temp->data = valor;
temp->next = NULL;

if (cabeza == NULL)
{
cabeza = temp;
cola = temp;
} else
{
cola->next = temp;
cola = temp;
}
return valor;
}

// regresa 1 (true) si la lista est vacia
int empty() { return ITEMS == 0; }


/* retirar elemento de la lista */
DATA_TYPE get()
{
nodo *temp;
DATA_TYPE d;

if ( empty() ) return -1;

d = cabeza->data;
temp = cabeza->next;
if (cabeza) delete cabeza;
cabeza = temp;
ITEMS --;
return d;
}

}; // fin de la clase QueueDin

/* punto de prueba */
int main()
{
QueueDin s;
DATA_TYPE d;

// llenando la cola
for (d='A'; d<='Z'; d++) {
s.put(d);
cout << d << " ";
}

cout << endl;
// vaciando la cola
while ( ! s.empty() )
cout << (DATA_TYPE)s.get() << " ";

cout << "\nPara terminar presione <Enter>...";
cin.get();
return 0;
}
Colas de doble enlace[editar]
Una cola doble es una estructuras en donde cada elemento puede
ser insertado y
recuperado por la parte del frente (cabeza) o por la parte de
atras (cola) de la
lista. A diferencia de una cola sencilla, en donde solo se
necesitan un mtodo para
leer y otro para escribir componentes en la lista, en una doble
cola debe haber dos
mtodos para leer ( uno para leer por el frente y uno para leer
por atras ) y dos
mtodos para escribir ( uno para escribir por el frente y uno
para escribir por atras ).

En el programa que se ver en seguida, se simula el comportamiento de una
estructura de cola doble con base en un arreglo esttico. En dicho programa se
declara e implementa la clase SDQueue con los siguientes mtodos:
put_front(), poner un elemento en el frente de la cola
put_back(), poner un elemento en la parte tracera de la
cola
get_front(), retirar un elemento de la parte frontal de la
cola
get_back(), retirar un elemento de la parte tracera de la
cola
empty(), regresa 1 (TRUE) si la cola est vacia
size(), nmero de elementos en la cola
Nota: observe que para los mtodos put_front() y get_front() se hace uso de la
funcin memmove(), esto es necesario debido al hecho de que put_front() tiene
que mover una posicin hacia atras todos los elementos en la lista antes de
insertar el componente indicado; por otro lado, la funcin get_front() tiene que
mover una posicin hacia adelante a todos los elementos que le siguen al primer
elemento.
Ejemplo: doble cola en un arreglo esttico
/*----------------------------------------------------------
--------+
+ ejemplo de una cola doble (DQUEUE) basada en un arreglo
est tico +
+ +
+ Autor: Oscar E. Palacios +
+ email: oscarpalacios1@yahoo.com.mx +
+ +
+ Manifiesto: +
+ Este programa puede distribuirse, copiarse y modificarse
de +
+ forma libre. +
+-----------------------------------------------------------
-------*/
#include <iostream.h>
#include <mem.h> // por memmove

// using namespace std;
#define MAX_SIZE 256
#define t_error -1;

typedef int DATA_TYPE; // mximo nmero de elementos
typedef int almacen[MAX_SIZE];

class SDQueue {
// atributos
int itemsize; // tamao de cada elemento
int items; // nmero de elementos
int cola, cabeza; // punteros de lectura y escritura
almacen alma; // el almacen o arreglo

public:
// constructor
SDQueue() : cola(0), cabeza(0), items(0),
itemsize(sizeof(DATA_TYPE)) {}

// destructor
~SDQueue() {}

int empty() { return items == 0; }

int size() { return items; }

/* agregar componente en la parte tracera de la lista */
DATA_TYPE put_back(DATA_TYPE valor)
{
if (items == MAX_SIZE) return t_error;
alma[cola] = valor;
items ++;
cola ++;
return valor;
}

/* agregar componente en la parte delantera de la lista */
DATA_TYPE put_front(DATA_TYPE valor)
{
if (items == MAX_SIZE) return t_error;
memmove((void *)&alma[cabeza+1], (void*)&alma[cabeza],
items*itemsize);
alma[cabeza] = valor;
items ++;
cola ++;
return valor;
}


/* retirar elemento de la parte frontal de la lista */
DATA_TYPE get_front()
{
DATA_TYPE d;

if ( empty() ) return t_error;
items --;
cola --;
d = alma[cabeza];
memmove((void*)&alma[cabeza], (void*)&alma[cabeza+1],
items*itemsize);
return d;
}

/* retirar elemento de la parte tracera de la lista */
DATA_TYPE get_back()
{
DATA_TYPE d;

if ( empty() ) return t_error;
items--;
cola --;
d = alma[cola];
return d;
}

}; // fin de la clase SDQueue

/* punto de prueba */
int main()
{
SDQueue s;
DATA_TYPE d;

for (d='A'; d<='Z'; d++) s.put_back(d);

while ( ! s.empty() )
cout << (char)s.get_front() << " ";

cout << "\nPara terminar presione <Enter>...";
cin.get();
return 0;
}
Una cola doblemente encadenada es una estructuras en donde cada elemento
puede ser insertado y recuperado por la parte del frente (cabeza) o por la parte de
atras (cola) de la lista. A diferencia de una cola sencilla, en donde solo se necesita
un puntero a un siguiente elemento, la estructura del nodo para una doble cola
debe poseer un puntero a un posible siguiente elemento y un puntero a otro
posible anterior elemento. Por ejemplo, para crear una estructura de nodo con
doble enlace para coleccionar nmeros enteros podemos usar la sintaxis:
struct nodo {
int data;
nodo *next, *prev;
};
Grficamente podemos imaginar la estructura anterior como:
+------+------+------+
<--| prev | data | next |-->
+------+------+------+
En el programa que se ver en seguida, se simula el comportamiento de una
estructura de cola de doble enlace. Para la implementacin de la clase DDqueue
en el programa se han elegido los mtodos:
put_front(), poner un elemento en el frente de la cola
put_back(), poner un elemento en la parte tracera de la
cola
get_front(), retirar un elemento de la parte frontal de la
cola
get_back(), retirar un elemento de la parte tracera de la
cola
empty(), regresa 1 (TRUE) si la cola est vacia
size(), nmero de elementos en la cola
/*----------------------------------------------------------
-----+
+ ejemplo de una cola doblemente enlazada (Dqueue) basada en
un +
+ arreglo dinmico +
+ +
+ Autor: Oscar E. Palacios +
+ email: oscarpalacios1@yahoo.com.mx +
+ +
+ Manifiesto: +
+ Este programa puede distribuirse, copiarse y modificarse
de +
+ forma libre. +
+-----------------------------------------------------------
----*/

#include <iostream.h>
#include <conio.h>

// using namespace std;

typedef char DATA_TYPE;

struct nodo {
DATA_TYPE data;
nodo *next, *prev;
};

class DDqueue {

int itemsize, items;
nodo *cola, *cabeza;


public:
// constructor
DDqueue() : cola(NULL), cabeza(NULL), items(0),
itemsize(sizeof(DATA_TYPE)) {}

// destructor
~DDqueue() {}


/* agregar componente en la parte tracera de la lista */
DATA_TYPE put_back(DATA_TYPE valor)
{
nodo *temp;

temp = new nodo;
if (temp == NULL) return -1;

temp->data = valor;

items ++;
if (cabeza == NULL )
{
temp->next = NULL;
temp->prev = NULL;
cabeza = temp;
cola = temp;
} else
{
cola->next = temp;
temp->prev = cola;
cola = temp;
cola->next = NULL;
}
return valor;
}

/* agregar componente en la parte frontal de la lista */
DATA_TYPE put_front(DATA_TYPE valor)
{
nodo *temp;

temp = new nodo;
if (temp == NULL) return -1;

temp->data = valor;

items ++;
if (cabeza == NULL )
{
temp->next = NULL;
temp->prev = NULL;
cabeza = temp;
cola = temp;
} else
{
cabeza->prev = temp;
temp->next = cabeza;
cabeza = temp;
cabeza->prev = NULL;
}
return valor;
}

// regresa true si la lista est vacia
int empty() { return items == 0; }


/* retirar elemento de la parte frontal lista */
DATA_TYPE get_front()
{
nodo *temp;
DATA_TYPE d;

if ( empty() ) return -1;

items --;
d = cabeza->data;
temp = cabeza->next;
if (cabeza) delete cabeza;
cabeza = temp;
return d;
}

/* retirar elemento de la parte tracera de la lista */
DATA_TYPE get_back()
{
nodo *temp;
DATA_TYPE d;

if ( empty() ) return -1;

items--;
d = cola->data;
temp = cola->prev;
if (cola) delete cola;
cola = temp;
return d;
}

}; // fin de la clase DDqueue

/* punto de prueba */
int main()
{
clrscr();

DDqueue s;
DATA_TYPE d;

// insertando elementos en la parte tracera
for (d='A'; d<='Z'; d++) s.put_back(d);

// insertando en la parte delantera
for (d=9; d>=0; d--)s.put_front(d+'0');

// vaciando la lista
while ( ! s.empty() )
cout << (DATA_TYPE)s.get_front() << " ";

cout << "\nPara terminar presione <Enter>...";
cin.get();
return 0;
}
Plantillas
Programacin en C++/Plantillas
Editores:
Oscar E. Palacios
Estructuras II Excepciones
Contenidos
[ocultar]
1 Plantillas
o 1.1 Introduccin
o 1.2 Un paso hacia adelante
o 1.3 Una mejor solucin
o 1.4 La clase vector desde la perspectiva de la POO
o 1.5 Una plantilla para la clase vector
Plantillas[editar]
Introduccin[editar]
Con el objeto de explicar la razn de la necesidad de la existencia de las plantillas debemos
reflexionar sobre tres paradgmas de programacin anteriores, estas son: programacin
clsica o procedimental, programacin estructurada y programacin orientada al objeto POO.
Programacin clsica

En el tipo de programacin conocida como clsica existe una clara diferenciacin entre los
datos y su manipulacin, es decir, entre los datos y el conjunto de algoritmos para manejarlos.
Los datos son tipos muy simples y generalmente los algoritmos se agrupan en funciones
orientadas de forma muy especfica a los datos que deben manejar. Por ejemplo, si se escribe
una funcin ( sort ) para ordenar en forma ascendente o descendente los nmeros contenidos
en un arreglo de nmeros enteros, dicha funcin puede aplicarse a cualquier arreglo de
enteros ms no a arreglos de otro tipo. An as, la programacin clsica provee el soporte
necesario para la reutilizacin de cdigo ya que el cdigo de la funcin se escribe solamente
una vez y su reutilizacin se da por medio de un mecanismo conocido como llamada de
funcin.
Programacin estructurada

En la medida en que los datos que haba de manipular se iban haciendo cada vez ms
complejos se busco la forma de agruparlos de alguna manera bajo un mismo nombre, es as
como surjen las estructuras de datos. Muchos autores se refieren a la programacin estructura
como a la suma de funciones y/o procedimientos ms estructura de datos.
Programacin Orientada al Objeto

La Programacin Orientada al Objeto ( POO ) introduce nuevas facilidades y se extiende el
concepto de dato, permitiendo que existan tipos ms complejos, es decir, si la programacin
estructurada establece las bases para la manipulacin de funciones y datos estructurados, la
POO establece las bases para manipular datos y funciones como un solo objeto. Esta nueva
habilidad viene acompaada por ciertas mejoras adicionales: la posibilidad de ocultacin de
determinados detalles internos irrelevantes para el usuario y la capacidad de herencia simple
o mltiple.
Notas: El ocultamiento de cdigo as como la herencia estn presentes ( en una forma simple
) en la programacin estructurada, y los mismos adquieren mucha ms relevancia en la POO.
Por ejemplo, en la programacin estructurada si usted escribe una librera de funciones, al
usuario de dicha librera solamente le informar de la existencia de tal o cual funcin, as como
el objetivo y la forma correcta para comunicarse con estas, pero no es necesario que se le
explique el funcionamiento interno de las mismas. Por otro lado, es bien conocido que
lenguajes tales como Pascal y C, por ejemplo, dan el soporte para la creacin de datos
estructurados ( Record en Pascal, y struct en C ), y que dichas estructuras pueden contener a
otras estructuras previamente definidas. De tal manera vemos como a los usuarios de las
funciones se les oculta el cdigo de las mismas, y que una estructura que contiene a otra
hereda los miembros de la estructura contenida.
Programacin genrica

La programacin genrica est mucho ms centrada en los algoritmos que en los datos, y su
postulado fundamental puede sintetizarse en una palabra: generalizacin. Significa que, en la
medida de lo posible, los algoritmos deben ser parametrizados al mximo y expresados de la
forma ms independiente posible de detalles concretos, permitiendo as que puedan servir
para la mayor variedad posible de tipos y estructuras de datos.
Con el objetivo de mostrar de una manera practica las diferencias entre los tres tipos de
programacin mencionados arriba tomaremos como base el modelo de una vieja estructura de
datos amiga de los programadores, me refiero a un array, tambin conocida por muchos como
arreglo, tabla o lista. Para no entrar en polemicas de estndarizacin de nombrado en este
captulo diremos que la estructura modelo con la que trabajaremos es un vector ( arreglo
unidimensional ).
Pues bien, dado un vector cualquiera se presenta la necesidad de crear un cierto nmero de
funciones que sean las encargadas de la manipulacin de los datos dentro del vector. Para
comenzar, podemos pensar en las funciones:
1. mostrar, para desplegar o imprimir los elementos del vector.
2. ordenar, para ordenar los elementos del vector.
3. buscar, para determinar la presencia o ausencia de un determinado elemento dentro
del vector.
4. insertar, para agregar componentes al vector.
5. eliminar, para quitar componentes del vector.
6. capacidad, para obtener la capacidad mxima del vector.
7. cuenta, para obtener el nmero de elementos actuales contenidos por el vector.
Al hacer un anlisis muy detallado del problema planteado y al tratar de resolver el mismo
mediante la programacin clsica, veremos que, si bien es cierto que se puede llegar a la
solucin, para lograrlo se tendran que establecer una serie de medidas que nos permitiern
controlar de alguna manera detalles tales como: el total de elementos soportados por el vector
y el nmero de elementos actuales contenidos por el vector. Por ejemplo, con la instruccin:
int vector[120];
se crea un arreglo con capacidad para 120 componentes de tipo entero . Ahora bien, el
compilador sabe perfectamente que deber reservar un espacio de 120 enteros para la
memoria del vector, pero no se garantiza que cualquier funcin trate de leer o escribir datos
fuera de los limites del vector. Es decir, nuestro programa no podra saber el tamao del
vector a menos que usaramos algn truco, por ejemplo usar el primer elemento del vector
para contener el tamao del mismo. Otra forma de alcanzar una solucin, sera que a cada
una de las funciones que tengan que ver con el vector se le pasar los parmetros: puntero de
vector y nmero de elementos en el vector, de tal manera que, por ejemplo, la funcin mostrar
podra declararse como:
int mostrar(int *vector, int cuenta);
Un paso hacia adelante[editar]
Si continuamos en el mbito de la programacin clsica podemos dar un paso ms si es que
nos valemos de tipos estructurados ms elaborados. Por ejemplo, podemos definir una
estructura llamada vector la cual posea los miembros: capacidad, cuenta y data como se
muestra en seguida:
typedef struct vector {
int capacidad;
int cuenta;
int *data;
};
De tal manera que podriamos escribir funciones que operen sobre un solo parmetro del tipo
estructurado vector. Por ejemplo, la funcin mostrar podra declararse como:
int mostrar(vector *v);
En este punto tendramos que detenernos y pensar en lo siguiente:
La estructura vector ( definida arriba con typedef ) es solamente un nuevo tipo de dato, es
decir, podemos declarar tantas copias ( variables ) de la misma como sean necesarias, pero
carece de un mtodo constructor adecuado. Por ejemplo, la declaracin:
vector nombre_var;
es vlida siempre y cuando que el tipo vector ya haya sido definido, pero la variable
nombre_var contendr slo basura hasta que no se establezcan los valores adecuados para
cada uno de sus miembros ( capacidad, cuenta y data ).
Una mejor solucin[editar]
Para el tipo de problemas como en el ejemplo vector y otros similares, surge la POO, misma
que facilita en gran medida la solucin del mismo, pero an queda pendiente la resolucin a
otro problema, es decir, hasta aqu hemos mencionado la estructura vector como un
contenedor de nmeros enteros, pero un vector podra contener caracteres, nmeros de punto
flotante y otros tipos estructurados; y los mismos algoritmos usados para ( mostrar, ordenar,
buscar, etc. ) empleados en un vector de enteros, tendran su aplicacin sobre vectores de
cualquier tipo. Es as como surge lo que se conoce como PLANTILLAS o lo que es lo mismo,
la programacin genrica.
La clase vector desde la perspectiva de la POO[editar]
Con el objetivo de mostrar en la prctica los conceptos que hemos venido mencionando
presentaremos un pequea implementacin de la clase vector. Se debe aclarar que la
implementacin de la misma se har para vectores contenedores de datos tipo int solamente.
Para simplificar el ejemplo, para la clase vector solamente se implementarn los mtodos
mostrar(), ordenar() e insertar(), as como un mtodo constructor base y un mtodo destructor.
#include <iostream>
#include <cstdio>
#include <ctime>

using namespace std;

#define VECTOR_DEFAULT_SIZE 128

class vector
{
// atributos
int capacidad;
int cuenta;
int *data;

public:
// constructor base
vector()
{
capacidad = VECTOR_DEFAULT_SIZE;
cuenta = 0;
data = new int[VECTOR_DEFAULT_SIZE];
}

// destructor
~vector() { delete[] data; }

// despliega todos los elementos contenidos por el vector
void mostrar()
{
for (int t = 0; t < cuenta; t++)
cout << "elemento " << t << ", valor " << data[t] << endl;
}

// inserta un elemento al vector
int insertar(int d)
{
if (cuenta == capacidad) return -1;
data[cuenta] = d;
cuenta ++;
return cuenta;
}

// ordena en forma ascendente los elementos del vector
void ordenar()
{
int i, j, temp;
int fin = cuenta;

i = 0;
while (i < fin )
{
for ( j = i ; j < fin-1; j++)
if ( data[j] > data[j+1] )
{
temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
}
fin --;
}
}
};


#define MAX 10
int main()
{
vector v;
srand( time(NULL) );
for (int r = 0; r < MAX; r++) v.insertar( rand() % 100);
cout << "\nvector v sin ordenar\n";
v.mostrar();

v.ordenar();
cout << "\nvector v ordenado\n";
v.mostrar();

getchar();
return 0;
}
Una plantilla para la clase vector[editar]
Una vez que se llegado al entendimiento de la programacin estructurada as como de la
programacin orientada al objeto, se puede observar que, si bien es cierto que ambas ofrecen
soluciones a problemas fundamentales tambin es cierto que las soluciones se presentan
como casos especializados. Esta ltima afirmacin la podemos ilustrar si nos fijamos en el
caso del programa presentado anteriormente, en dicho programa se presenta la clase vector
como un contenedor especial para nmeros enteros (int), ahora bien, si prestamos an aun
ms atencin podemos llegar a la conclusin de que todos los algoritmos o funciones
aplicadas en la clase vector pueden operar con cualquier otro tipo de datos y, por lo tanto, la
nica diferencia sera el tipo de datos contenidos por el vector. De tal manera que aparece lo
que se llama generalizacin o programacin genrica y esta, a su vez, nos permite la
creacin de plantillas basadas en una lgica operatoria previamente concebida.
Con el objetivo de mostrar un ejemplo prctico retomaremos la clase vector del programa de la
seccin anterior y crearemos, a raiz del mismo, una plantilla. La plantilla resultante tendr la
capacidad para crear vectores de cualquier tipo.
#include <iostream>
#include <cstdio>
#include <ctime>

using namespace std;

#define VECTOR_DEFAULT_SIZE 128

template <class T> class vector
{
// atributos
int capacidad;
int cuenta;
T *data;

public:
// constructor base
vector()
{
capacidad = VECTOR_DEFAULT_SIZE;
cuenta = 0;
data = new T[VECTOR_DEFAULT_SIZE];
}

// destructor
~vector() { delete[] data; }

void mostrar();
int insertar(T d);
void ordenar();
};

// implementacin del mtodo mostrar
template <class T> void vector<T>::mostrar()
{
for (int t = 0; t < cuenta; t++)
cout << "elemento " << t << ", valor " << data[t] << endl;
}

// implementacin del mtodo insertar
template <class T> int vector<T>::insertar(T d)
{
if (cuenta == capacidad) return -1;
data[cuenta] = d;
cuenta ++;
return cuenta;
}

// implementacin del mtodo ordenar
template <class T> void vector<T>::ordenar()
{
T temp;
int i, j, fin = cuenta;

i = 0;
while (i < fin )
{
for ( j = i ; j < fin-1; j++)
if ( data[j] > data[j+1] )
{
temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
}
fin --;
}
}


#define TEST 10
int main()
{
// prueba de un vector de nmeros de punto flotante
vector<double> v;
srand( time(NULL) );
for (int r = 0; r < TEST; r++) v.insertar( (rand() % 10) * 0.5);
cout << "\nvector v sin ordenar\n";
v.mostrar();
v.ordenar();
cout << "\nvector v ordenado\n";
v.mostrar();

// prueba de un vector de nmeros long int
vector<long int> v2;
srand( time(NULL) );
for (int r = 0; r < TEST; r++) v2.insertar( (rand() % 100) );
cout << "\nvector v2 sin ordenar\n";
v2.mostrar();
v2.ordenar();
cout << "\nvector v2 ordenado\n";
v2.mostrar();

getchar();
return 0;
}
Excepciones
Programacin en C++/Excepciones
Plantillas Librera Estndar de Plantillas
Contenido
[ocultar]
1 Excepciones. Motivacin histrica
2 Conformacin de los bloques try y catch
3 Control de excepciones
o 3.1 Excepciones genricas
o 3.2 Excepciones de clases
o 3.3 La clase exception
Excepciones. Motivacin histrica[editar]
Primeramente, antes de entrar en el tema de las excepciones en programacin, se ha de
matizar en el concepto de qu son las excepciones, vistas desde un punto de vista fuera y
dentro del mundo de la programacin.
En el lenguaje humano, una excepcin es un elemento excluyente de una regla, y de forma
convencional se ha extendido esta definicin. En el lenguaje mquina, una excepcin se trata,
de forma general, de algo que no se espera que ocurra, pero que puede ocurrir, similar al
tratamiento de errores, pero de los errores en tiempo de ejecucin.
A veces estas excepciones, para una mquina, no son casos que no deberan estar
contemplados, tal y como un programador se lo asigna, sino que pueden ser indicadores para
comprobar que realmente todo est marchando bien o no.
En los programas de ordenador hechos en C existi durante mucho tiempo la costumbre de
usar el comando "goto" (tambin implementada en C++), pero ste se ha ido eliminando
progresivamente de casi todos y cada uno de los cdigos y programas que han ido surgiendo.
El significado de la funcin 'goto' no forma parte del libro actual, pero se pueden buscar
referencias por internet donde se especifique con ms detalle qu es.
Como una de las formas de control de errores ms usuales era con goto, se usaron otras
variantes, como las aserciones de cdigo (assertions, en ingls) o, con la llegada de la
programacin orientada a objetos, de los comandos try, catch y throw.
Conformacin de los bloques try y catch[editar]
Por norma general, los comandos try y catch conforman bloques de cdigo.
Cada uno de estos bloques se recomienda, aunque sea de una nica lnea, envolverlos en
llaves, como muestra el siguiente ejemplo:
// ...cdigo previo...
try
{
// bloque de cdigo a comprobar
}
catch( tipo ) // Ha ocurrido un suceso en el try que se ha terminado
//la ejecucin del bloque y catch recoge y analiza lo sucedido
{
// bloque de cdigo que analiza lo que ha lanzado el try
}
// ...cdigo posterior...
Generalmente entre el try y el catch no se suele insertar cdigo, pero se insta al lector a que lo
intente con su compilador habitual y que compruebe si hay errores o no de compilacin.
Control de excepciones[editar]
Una excepcin es un error que puede ocurrir debido a una mala entrada por parte del usuario,
un mal funcionamiento en el hardware, un argumento invlido para un clculo matemtico, etc.
Para remediar esto, el programador debe estar atento y escribir los algoritmos necesarios para
evitar a toda costa que un error de excepcin pueda hacer que el programa se interrumpa de
manera inesperada. C++ soporta una forma ms directa y fcil de ver tanto para el
programador como para los revisores del cdigo en el manejo de excepciones que su smil en
el C estndar y esta consiste, tratndose del lenguaje C++, en el
mecanismo try, throw y catch.

La lgica del mecanismo mencionado consiste en:
1. Dentro de un bloque try se pretende evaluar una o ms expresiones y si dentro de
dicho bloque se produce unalgo que no se espera se lanza por medio de throw una
excepcin, la misma que deber ser capturada por un catchespecfico.
2. Puesto que desde un bloque try pueden ser lanzados diferentes tipos de errores de
excepcin es que puede haber ms de un catch para capturar a cada uno de los
mismos.
3. Si desde un try se lanza una excepcin y no existe el mecanismo catch para tratar
dicha excepcin el programa seinterumpir abruptamente despues de haber pasado
por todos los catchs que se hayan definido y de no haber encontrado el adecuado.
4. Los tipos de excepciones lazados pueden ser de un tipo primitivo tal
como: int,float, char, etc. aunque normalmente las exepciones son lanzadas por
alguna clase escrita por el usuario o por una clase de las que vienen incluidas con el
compilador.
En el programa que se listar a continuacin muestra un ejemplo de como lanzar una
excepcin de tipo int dentro del bloque try, y cmo capturar la excepcin por medio de catch.
Ejemplo
// Demostracin de los comandos try, throw y catch
#include <iostream>

// Funcin: main
// Recibe: void
// Devuelve: int
// En la funcin principal se tratarn los comandos try, throw y
catch
int main(void)
{
try // Se intenta hacer el siguiente cdigo
{
// Aqu puede ir ms cdigo...
throw 125; //...aunque directamente en este caso se lanza una
excepcin.
}
catch(int) // Se captura con un catch de enteros (podra usarse long
o char, por ejemplo)
{
std::cout << "Ha surgido una excepcin de tipo entero" <<
std::endl; // y se muestra por pantalla
}

std::cin.get(); // Y el programa finaliza.

return 0;
}
Excepciones genricas[editar]
Como ya se ha mencionado, los errores pueden deberse a una multitud de situaciones
muchas veces inesperadas, por tal motivo, en C++ existe una forma de manejar excepciones
desconocidas ( genricas ) y es buena idea que si se est escribiendo un controlador de
excepciones incluya un catch para capturar excepciones inesperadas. Por ejemplo, en el
siguiente progama se escribe un catch que tratar de capturar cualquier excepcin
inesperada.
// Demostracin: try, throw y catch
#include <iostream>

using namespace std;

int main()
{
try {
throw 125;
}
catch(...) {
cout << "Ha ocurrido un error inesperado..." << endl;
}
cin.get();
return 0;
}
Excepciones de clases[editar]
Si usted est usando una clase escrita por terceras personas o de las que se incluyen con el
compilador y desea utilizar el mecanismo try, deber conocer el tipo de excepcin lanzado por
dicha clase para as poder escribir el catchcorrespondiente para el tratamiento de dicho error.
Por ejemplo, la funcin at() de la clasestring ( que ser estudiada ms adelante ) lanza una
excepcin cuando se trata de leer o escribir un componente fuera de rango. En tales casos
usted puede proceder a capturar el error como se muestra en el siguiente programa.
// Compilado y probado exitosamente con Dev-C++
// Demostracin: excepcin de la clase string

#include <iostream>
#include <string>

using namespace std;

int main()
{
string s = "Hola";

try {
cout << s.at(100) << endl;
}
catch(exception& e) {
cout << e.what() << endl;
}

cin.get();
return 0;
}
En el programa anterior el mtodo at de la clasestring lanzar ( throw-up ) un error de
excepcin, ya que la instruccin s.at(100) trata de acceder a un elemento fuera de los limites
del objeto ( s ).
La clase exception[editar]
Tal como se mostr en el programa anterior, los errorres generados por las libreras estndar
de C++ pueden ser capturados por un catch que tome un parmetro tipo exception.
Realmente, exception es una clase base de donde usted puede derivar las suyas y
sobrescribir los mtodos para el tratamiento de excepciones. La clase exception est incluida
en la libreria<exception> y su estructura es la siguiente:
class exception {
public:
exception() throw() { }
virtual ~exception() throw();
virtual const char* what() const throw();
};
En muchos casos bastar con sobrescribir el mtodo what() en la clase derivada de
exception, ya que dicho mtodo es el encargado de generar el mensaje que trata de explicar
la naturaleza del error ocurrido. En el programa que veremos en seguida, se da un ejemplo
sencillo de cmo crear una clase derivada de la clase exception con el objetivo de sobrescribir
el mtodo what().
// Demostracin: sobrescritura del mtodo what()
#include <iostream>
#include <cstdlib>
#include <exception>

using namespace std;

class div_cero : public exception
{
public:
const char* what() const throw()
{
return "Error: divisin por cero...";
}
};

int main(int argc, char *argv[])
{
double N, D;
cout << "Probando divisin" << endl;
cout << "Ingrese el numerador :";
cin >> N;
cin.clear();

cout << "Ingrese el denominador :";
cin >> D;
cin.clear();

try {
if (D == 0) throw div_cero();
cout << N << " / " << D << " = " << N/D << endl;
}
catch(exception& e) {
cout << e.what() << endl;
}

system("PAUSE");
return 0;
}

Siguiendo la misma metodologa mostrada por el programa anterior, usted puede crear clases
independientes para capturar errores de excepciones especficas. Por ejemplo, si se desea
crear una serie de funciones matemticas se deben considerar los sucesos de errores tales
como: Divisin por cero, Error de dominio, Error de rango, etc. As, el siguiente programa
puede ser un buen ejemplo para que usted escriba sus propios controladores de mensajes de
error. Observe cmo en el programa se crea la clase ErrorMat y dentro de la misma la
funcin porque() la cual se encargar de desplegar el mensaje de error. Aunque ErrorMat solo
ha sido pensada para tratar los posibles errores de rango y errores de dominio, la misma
puede rescribirse para capturar todos los errores posibles que puedan resultar a raiz de
operaciones matemticas.

Nota: No deje de observar tambin, cmo la funcin independiente logaritmo() verifica si el
parmetro pasado a la misma es 0 o menor que 0 y en tales circunstancias se lanzara (throw)
un error de excepcin del tipo ErrorMat ya que el dominio para la funcin log() es el de los
nmeros positivos y el logaritmo de cero no est definido en los nmeros reales.
// Demostracin: try, throw y catch

#include <iostream>
#include <cmath>

using namespace std;

static const int EDOMINIO=100;
static const int ERANGO=101;

class ErrorMat
{
public:
ErrorMat() : motivo(0) {};
ErrorMat(int m) : motivo(m) {};
const char* porque() const throw();

private:
int motivo;
};

const char* ErrorMat::porque() const throw()
{
switch (motivo)
{
case EDOMINIO: return "Error de Dominio ";break;
case ERANGO: return "Error de Rango ";break;
default: return "Error Desconocido"; //En rigor no debera
ocurrir
}
}

double logaritmo(const double n)
{
try {
if (n < 0) throw(ErrorMat(EDOMINIO) );
if (n == 0) throw(ErrorMat(ERANGO) );
return log(n);
}
catch(ErrorMat& e) {
cout << e.porque();
}
return 0;
}

int main()
{
double r = 100;
cout << "log(" << r << ") = " << logaritmo(r) << endl;
cout << "log(-" << r << ") = " << logaritmo(-r) << endl;
cin.get();
return 0;
}
Librera Estndar de Plantillas
Programacin en C++/Librera Estndar de Plantillas
Editores:

Oscar E. Palacios
Biblioteca estndar de plantillas[editar]
Vectores Colas de Listas Pilas Colas Colas con Sets Maps Bitsets Iteradores

doble fin (stack) (queue) prioridad
La STL (Standard Template Library) de C++ es una coleccin genrica de plantillas de clases
y algoritmos que permite a los programadores implementar fcilmente estructuras estndar de
datos como colas (queues), listas (lists), y pilas (stacks).
La STL de C++ provee a los programadores con lo constructores siguientes, agrupados en
tres categorias:
Secuencias (sequences)
1. C++ Vectors
2. C++ Lists
3. C++ Double-Ended Queues
Adaptadores de contenedor (Container Adapters)
1. C++ Stacks
2. C++ Queues
3. C++ Priority Queues
Contenedores asociativos (Associative Containers)
1. C++ Bitsets
2. C++ Maps
3. C++ Multimaps
4. C++ Sets
5. C++ Multisets
La idea detras de la STL de C++ es que la parte dificil en el uso de estructuras complejas de
datos ya ha sido previamente completada. Por ejemplo, si un programador desea usar un
stack de enteros, todo lo que tiene que hacer es escribir el cdigo:
stack<int> myStack;
Con un minimo de esfuerzo, l o ella puede usar la funcin push() para ingresar enteros al
stack; y la funcin pop() para retirar enteros del stack. A travez de la magia de las plantillas de
C++, se puede especificar cualquier tipo de dato, no slo enteros. La clase Stack de la STL
provee la funcionalidad genrica de un stack, sin importar el tipo de dato en el stack.
Vectores
Colas de doble
fin
Listas Pilas (stack) Colas (queue)
Colas con
prioridad
Iteradores

Iteradores[editar]
El termino iterar significa (en palabras sencillas) el mtodo o forma que se usa para poder
navegar sobre los elementos de una lista especfica. Luego, un iterador es como una especie
de "puntero especial" que nos permite leer o escribir valores sobre cada uno de los elementos
en una lista. Los iteradores pueden ser comparados con los ndices que se emplean para leer
o escribir valores sobre los elementos de una lista. Igual a lo que sucede con los tipos de
datos dentro de un arreglo primitivo en donde para leer o escribir valores sobre los elementos
se tiene que prestar atencin al tipo de dato, un iterador tiene que ser del tipo de dato que
posee la lista. En ese sentido, si tenemos por ejemplo un vector que posee datos de tipo
entero (int) entonces el iterador tendr que ser de tipo entero; si por el contrario se tiene un
vector cuyos datos son del tipo cadena (string) entonces el iterador tiene que ser del tipo
cadena.

Sintaxis

La sintaxis general para la declaracin de un iterador es:

NombrePlantilla<tipo>::iterator varid;

Donde,
NombrePlantilla Es el nombre de una STL
tipo
Es el tipo usado para la
plantilla
::iterator
Es el mtodo para obtener el
iterador
varid Es el nombre de la variable

Por ejemplo, para obtener un iterador a unvector de tipo int podemos usar la instruccion:

vector <int>::iterator el_iterador;


A manera de ejemplo, vamos a mostrar un programa en el que se usar un iterador de
tipochar.
Nota: en el programa se hace uso de los mtodos begin para obtener un iterador
hacia el inicio del vector, y end para obtener un iterador hacia el final del mismo.
// Demostracion del uso de iteradores
// probado en: Dev-C++ 4.9.9.2

#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
vector<char> v;

for (int x = 'A'; x <= 'Z'; x++)
v.push_back(x);

// obtenemos un iterator del tipo char
vector<char>::iterator it;

// lectura y despliegue de datos
cout << "\ndesplegando datos" << endl;
for( it = v.begin(); it != v.end(); it++ )
cout << *it << endl;

system("PAUSE");
return EXIT_SUCCESS;
}
Iteradores reversos[editar]
La STL de C++ permite que los elementos de las listas creadas puedan ser navegados en
orden "normal", es decir desde el primero hasta el ltimo de los elementos agregados a la
lista, y para dichas tareas se usa un iterador normal. Tambin, los elementos pueden
navegarse en orden "reverso" y en tales casos se usa un iterador en reverso
( reverse_iterator ). Un ejemplo de reverse_iterator se muestra en el siguiente programa.

Notas:
Se debe de observar que para obtener iteradores normales se usan (generalmente)
los mtodos begin() y end(), mientras que que para obtener iteradores reversos se
emplean los mtodos rbegin() y rend().
Los iteradores reversos se comportan de manera inversa. Por ejemplo, para obtener
un iterador que vaya desde el final hasta el inicio de los elementos, se usa la
funcinrbegin() la cual regresar un iterador para procesar la lista desde el ltimo
hasta el primero de los elementos. En contraparte, la funcin begin() regresa un
iterador para procesar la lista desde el primero hasta el ltimo de los elementos. Es
decir, begin() regresa una referencia hacia el primer elemento, mientras que rbegin()
regresa una referencia hacia el ltimo elemento.
// Demostracion del uso de iteradores reversos
// probado en: Dev-C++ 4.9.9.2

#include <cstdlib>
#include <iostream>
#include <list>

using namespace std;

int test()
{
list<char> v;

for (int x = 'A'; x <= 'Z'; x++) v.push_back(x);
cout << endl;

cout << "orden original" << endl;
// creamos un iterator normal
list<char>::iterator i = v.begin();
while(i != v.end() )
{
cout << *i++ << " ";
}
cout << endl;

cout << "orden inverso" << endl;
// creamos un iterator reverso
list<char>::reverse_iterator ri = v.rbegin();
while(ri != v.rend() )
{
cout << *ri++ << " ";
}
cout << endl;
return 0;
}


int main(int argc, char *argv[])
{
test();
system("PAUSE");
return EXIT_SUCCESS;
}
http://es.wikibooks.org/wiki/Programaci%C3%B3n_en_C%2B%2B/Librer%C3%ADa_Est%C3%A1nd
ar_de_Plantillas

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