You are on page 1of 63

Notas del lenguaje C++

Federico Amndola
Martn Fernndez
Consultas y sugerencias: laboratorio.ayda@alumnos.exa.unicen.edu.ar
Licencia creative commons Atribucin-Compartir Obras Derivadas Igual 2.5 Argentina
http://creativecommons.org/licenses/by-sa/2.5/ar/
Usted es libre de:
COPIAR, DISTRIBUIR, EXHIBIR Y EJECUTAR LA OBRA
HACER OBRAS DERIVADAS
Bajo las siguientes condiciones:
Atribucin: Usted debe atribuir la obra en la forma especificada por el autor o el licenciante.
Compartir Obras Derivadas Igual. Si usted altera , transforma, o crea sobre esta obra, slo podr distribuir la
obra derivada resultante bajo una licencia idntica a sta.
ndice de contenido
Introduccin.........................................................................................................1
Programas...........................................................................................................2
Identificadores.................................................................................................2
Bloques............................................................................................................2
Tipos y Variables..................................................................................................3
Declaracin......................................................................................................3
mbito de las !ariables...................................................................................3
Visibilidad........................................................................................................."
Tipos b#sicos de $%%......................................................................................&
'ecuencias de escape......................................................................................(
$onstantes.......................................................................................................(
)numeraciones................................................................................................*
+egistros..........................................................................................................*
,rreglos............................................................................................................-
.peradores........................................................................................................../
)structuras de control.......................................................................................11
)structuras de seleccin................................................................................11
'entencia if................................................................................................11
'entencia s0itc1........................................................................................11
)structuras de iteracin.................................................................................12
'entencia 01ile..........................................................................................12
'entencia do201ile.....................................................................................12
'entencia for..............................................................................................12
3unciones...........................................................................................................1"
Declaracin....................................................................................................1"
Definicin.......................................................................................................1"
Pasa4e de par#metros....................................................................................1&
'obrecarga de funciones...............................................................................1(
3unciones recursi!as......................................................................................1*
$omparacin entre iteracin y recursin...................................................1*
,rgumentos de los programas.......................................................................1-
Bibliotecas.........................................................................................................1/
Directi!a include............................................................................................1/
)spacios de nombres.....................................................................................1/
Bibliotecas para las funciones m#s comunes................................................25
6ane4o de entrada7salida por consola...............................................................21
6ane4o de la consola en $%%........................................................................21
'alida por consola .....................................................................................21
)ntrada por consola...................................................................................21
'incroni8acin de la entrada..................................................................22
9eer l:neas completas.............................................................................22
$onfiguracin del formato de la entrada y la salida...................................2"
6ane4o de la consola en $.............................................................................2"
)ntrada por consola...................................................................................2&
6ane4o de cadenas............................................................................................2(
$adenas de $%%...........................................................................................2(
$adenas de $.................................................................................................2(
.peraciones de entrada7salida por consola...............................................2*
6ane4o de arc1i!os............................................................................................2/
'treams de arc1i!os de $%%.........................................................................2/
,rc1i!os de te;to.......................................................................................35
,rc1i!os binarios........................................................................................32
'treams de arc1i!os de $..............................................................................3&
,rc1i!os de te;to.......................................................................................3(
,rc1i!os binarios........................................................................................3*
Punteros y mane4o de memoria.........................................................................3/
.peradores relacionados con punteros.........................................................3/
.peraciones para obtener y liberar memoria................................................"5
.peraciones para obtener memoria.........................................................."5
.peraciones para liberar memoria............................................................."1
$onsideraciones sobre la utili8acin de malloc y free................................"2
.bteniendo bloques de memoria contigua................................................"2
,rreglos y punteros........................................................................................"3
,rreglos como par#metros de funciones....................................................""
,rreglos din#micos....................................................................................."&
,ritm<tica de punteros.................................................................................."(
$lases................................................................................................................"-
Definicin de clases 2 Declaracin de la interfa8..........................................."-
Instanciacin y uso........................................................................................"/
Definicin7Implementacin de la interfa8......................................................&5
6<todos consultores......................................................................................&1
$onstructores.................................................................................................&1
Destructor......................................................................................................&"
'obrecarga de operadores.............................................................................&"
.perador de salida de streams..................................................................&&
.perador de asignacin.............................................................................&(
9a palabra reser!ada t1is..............................................................................&(
$lases parametri8adas...................................................................................&*
=erencia.........................................................................................................&/
Introduccin
El lenguaje que se utilizar durante la cursada de la ctedra de Anlisis y Diseo de Algoritmos I y II es
C++.
C++ tiene sus races en el lenguaje de programacin C. El lenguaje C es imperatio y procedural!
orientado a la implementacin de sistemas operatios y por ello es que cuenta con caractersticas de "ajo
niel #es decir! permite operaciones dependientes directamente de la arquitectura de la mquina$. %i "ien
C tam"i&n 'ue utilizado para el desarrollo de aplicaciones de usuario! en la actualidad su uso principal es
en el desarrollo de so't(are "ase o de sistemas) compiladores! sistemas operatios! "i"liotecas! sistemas
em"e"idos! etc* de"ido a su simplicidad y a que! al utilizar operaciones cercanas a la arquitectura de la
mquina su"yacente! nos permite conocer e+actamente lo que nuestro programa est realizando y
desarrollar t&cnicas que optimicen el 'uncionamiento del mismo.
C++ es una extensin del lenguaje C desarrollado en 1979, que introduce el soporte para la abstraccin de
datos, la programacin orientada a objetos y la programacin genrica. Por esto se dice que C++ es un
lenguaje multi-paradigma (permitiendo mezclar la programacin procedural y la programacin orientada
a objetos). Las caractersticas que agrega C++ son: clases, herencia mltiple, polimorfismo, sobrecarga de
operadores, plantillas y manejo de excepciones. Todas estas caractersticas son propias de lenguajes de
alto nivel, por lo que C++ se considera un lenguaje con un nivel de abstraccin mucho mayor que C
(aunque sigue manteniendo las caractersticas de bajo nivel de C). Es por esto que, el lenguaje C++, es
ms apropiado que C para el desarrollo de aplicaciones grandes gracias a la mayor facilidad y rapidez de
desarrollo que brindan sus caractersticas avanzadas.
C++ tiene la misma sinta+is e implementa casi todas las caractersticas de C! de 'orma que la mayora de
los programas escritos en C compilaran con un compilador de C++! sin la necesidad de realizar cam"ios
en el cdigo 'uente. ,or otra parte! si "ien se realizan es'uerzos para ma+imizar la compati"ilidad entre
am"os lenguajes! los mismos son independientes #de -ec-o! el estndar de C++ no soporta todas las
caractersticas del estndar de C y -ay puntos donde los mismos entran en con'licto
.
$. /eniendo en cuenta
lo anterior y dejando de lado las de'iniciones estrictas! conceptualmente! podemos considerar que C++ es
un superconjunto de C! como se indica en la siguiente 'igura.
El estndar del lenguaje C++ se sigue actualizando con el paso de los aos, ratificando y agregando
nuevas caractersticas para mejorar la experiencia a la hora de desarrollar aplicaciones. La ltima
actualizacin fue en el ao 2011 y se espera otra para el 2014. Tambin es importante mencionar que
existen muchos compiladores de C++, comerciales y libres, donde cada uno adopta el estndar del
lenguaje de una forma particular. Debido a esto, siempre es recomendable utilizar un compilador que se
ajuste y respete lo ms posible el estndar definido.
Al soportar todas las caractersticas de C, C++ puede considerarse un lenguaje complicado para aprender
y dominar. Esto viene de la confusin que surge de la posibilidad de realizar la misma operacin de varias
formas distintas, utilizando los mecanismos y el estilo de C o el de C++. Debido a esto, esta gua no
pretende cubrir todos los aspectos de este lenguaje (ni reemplazar la bibliografa recomendada), sino
introducir los mecanismos ms importantes, centrndose en aquellos ms complejos de una forma que
resulte lo ms clara posible.
1
Para una comparacin ms detallada ver http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 1
Programas
El siguiente es el programa ms simple que se puede realizar en C++:
int main()
{
return 0;
}
En C++ todo programa de"e implementar una 'uncin principal llamada main que de"e retornar un alor
entero indicando el resultado de la ejecucin del mismo* 0 si el programa 'inaliz normalmente o distinto
de 0 si ocurrieron errores durante su ejecucin.
Identificadores
Es el nombre que permite hacer referencia a las constantes, variables y funciones de un programa. Las
reglas para escribir identificadores son:
Deben comenzar con una letra o guin bajo.
Slo letras (A-Z, a-z), dgitos (0-9) o el guin bajo (_) pueden seguir al primer smbolo.
Una caracterstica del lenguaje de extrema importancia es que es case sensitive, es decir, que distingue
entre maysculas y minsculas a la hora de nombrar identificadores. Es por eso que main, Main,
MAIN, mAiN, etc, son considerados identificadores distintos en C++ (a diferencia de lo que sucede en
lenguajes como Pascal y BASIC, donde se considera que dichos nombres hacen referencia al mismo
identificador).
Bloques
Un bloque es una sentencia compuesta, se trata de una sucesin (que puede estar vaca) de sentencias
delimitadas por un par de corchetes {}:
{
<sentencia
1
>;
<sentencia
2
>;
<sentencia
3
>;
...
}
Desde el punto de vista sintctico, un bloque puede ser considerado como una sola sentencia.
Tericamente, los bloques pueden ser anidados a cualquier nivel (profundidad). El aspecto de los bloques
"anidados" es el siguiente:
{
...
{
<sentencia
1
>;
<sentencia
2
>;
<sentencia
3
>;
...
}
...
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 2
Tipos y Variables
Declaracin
Para utilizar una variable en C++, primero se debe declarar especificando el nombre de la variable (un
identificador vlido) y que tipo de datos se quiere almacenar:
<tipo> <variable
2
> <variable
2
> ... <variable
n
>;
Por ejemplo:
int a b c;
Es posible inicializar una variable en el mismo momento en que se declara:
<tipo> <variable
1
> = <valor!inicial>, <variable
2
> = <valor!inicial>, ...;
Por ejemplo:
int a"1 b"2 c"#;
mbito de las variables
Dentro de un programa se pueden encontrar dos tipos de mbito para las variables:
variables locales: nicamente visibles dentro de la funcin o bloque donde se han declarado y, de
hecho, no existen fuera de ese mbito. Las variables locales pueden ser declaradas en cualquier
parte de un bloque o funcin
2
pero slo podrn intervenir en sentencias posteriores a su
declaracin.
variables globales: declaradas exteriormente a las funciones, pueden ser utilizadas por aquellas
que fueron declaradas luego de las mismas.
$$ %eclaraci&n 'e variables (lobales a )*ncion
1
)*ncion
2
+ main
<tipo> <)*ncion
1
>
{
...
$$ %eclaraci&n 'e variables locales
...
}
$$ %eclaraci&n 'e variables (lobales a )*ncion
2
+ main
<tipo> <)*ncion
2
>
{
...
$$ %eclaraci&n 'e variables locales
...
}
...
$$ %eclaraci&n 'e variables (lobales a main
int main()
{
...
$$ %eclaraci&n 'e variables locales
...
}
2
A diferencia de C que exige que todas las variables se declaren al principio del bloque.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 3
Por ejemplo, analizando el siguiente fragmento de cdigo:
int a " 20;
int main(){
int b " 10;
{ $$ Inicio s*bblo,*e
int c " 1-;
co*t << ./ariable a0. << a;
co*t << ./ariable b0. << b;
co*t << ./ariable c0. << c;
} $$ 1in s*bblo,*e
co*t << ./ariable a0. << a;
co*t << ./ariable b0. << b;
co*t << ./ariable c0. << c; $$ 2rror0 c no est3 'eclara'a en este 3mbito
return 0;
}
La variable a es global a todo el archivo donde se encuentra el main, por lo tanto podr ser utilizada por
cualquier funcin o procedimiento que se defina luego de la declaracin de la variable.
La variable b es local a la funcin main y global a todos los bloques definidos dentro de la misma, como
por ejemplo, el subbloque. Dentro de este bloque se encuentra declarada la variable c, la cual es local al
subbloque. Fuera de este bloque, la variable c no es visible. La porcin de cdigo en donde cada variable
es visible se denomina alcance o mbito. Para las variables locales, el alcance comienza en la sentencia en
donde la variable est declarada y termina en la llave final que delimita el bloque en el cual fue definida.
Visibilidad
Un mismo identificador puede ser 1ocultado2 por otro del mismo nom"re declarado en un "loque interior
al primero. ,or ejemplo! la declaracin de una aria"le local puede 1ocultar2 una aria"le glo"al con el
mismo identi'icador)
int a " 20;
int main(){
int b " 10;
{ $$ Inicio s*bblo,*e
int b " 1-;
co*t << ./ariable A0 . << a << .4n.;
co*t << ./ariable 50 . << b << .4n.;
} $$ 1in s*bblo,*e
co*t << ./ariable A0 . << a << .4n.;
co*t << ./ariable 50 . << b << .4n.;
return 0;
}
En este caso! la aria"le b declarada como local en el su""loque! oculta a la aria"le b declarada en la
'uncin main* de"ido a esto! el resultado del cdigo anterior es el siguiente)
> /ariable A0 20
> /ariable 50 1-
> /ariable A0 20
> /ariable 50 10
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 4
Tipos bsicos de C++
3
Nombre Descripcin Valores
c6ar Caracter (o un entero pequeo)
Los caracteres imprimibles del cdigo ASCII ms algunos no
imprimibles representados en el cdigo fuente a travs de secuencias
de escape.
0 1 2 3 4 5 6 7 8 9
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
_ $ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
<HT> <VT> <NL> <FF> <SPACE>
7!c6ar Caracter ancho Caracteres del juego de caracteres Unicode
4
.
int Enteros
con signo: -2147483648 a 2147483647
sin signo: 0 a 4294967295
)loat Punto flotante 3.4e +/- 38 (7 dgitos)
'o*ble
Punto flotante de doble
precisin
1.7e +/- 308 (15 dgitos)
bool Booleano true o false
voi' Ausencia de valor
Es un tipo especial que representa la ausencia de valor. Generalmente
se utiliza para indicar que una funcin no devuelve un valor o no
requiere ningn parmetro. Tambin tiene otras formas de uso que
involucran punteros, pero no se vern por el momento.
No est permitida la declaracin:
voi' <i'enti)ica'or>;
Modificadores opcionales
A excepcin de los tipos voi' y bool, los tipos bsicos pueden tener modificadores opcionales, que se
usan para modificar el significado del tipo base (en cuanto a rango de valores y espacio de
almacenamiento). Estos modificadores indican: con signo (si(ne'), sin signo (*nsi(ne'), largo
(lon() y corto (s6ort).
8si(ne'9*nsi(ne': 8s6ort9lon(9lon( lon(: <tipo> <i'enti)ica'or>;
Por ejemplo:
signed int a; $$ 2,*ivalente a0 int a;
unsigned int a;
unsigned long int a;
3os modi'icadores opcionales aplicados a un tipo "sico de'inen un nueo tipo! de 'orma que por
ejemplo! s6ort y *nsi(ne' s6ort son tipos distintos.
4n c6ar puede ser con signo #si(ne'$! sin signo #*nsi(ne'$! o no especi'icado* por de'ecto se
suponen con signo. 5ientras que slo se permite un modificador adicional (lon($! para el tipo 'o*ble!
dando lugar a los lon( 'o*ble.
3
El tipo w_char junto con el tipo bool son exclusivos de C++.
4
Para ver las ventajas de cdigo Unicode frente al ASCII ver http://www.i18nguy.com/UnicodeBenefits.html
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 5
A continuacin se presenta una ta"la con el rango de alores para todos los tipos 'undamentales)
Tipo Rango de valores
*nsi(ne' c6ar
0 <= X <= 255identificador
c6ar (si(ne')
-128 <= X <= 127
s6ort (si(ne')
-32,768 <= X <= 32,767
*nsi(ne' s6ort
0 <= X <= 65,535
*nsi(ne' (int)
0 <= X <= 4,294,967,295
int (si(ne')
-2,147,483,648 <= X <= 2,147,483,647
*nsi(ne' lon( (int)
0 <= X <= 4,294,967,295
lon( (int)
-2,147,483,648 <= X <= 2,147,483,647
)loat
32 1.18e-38 <= |X| <= 3.40e38
'o*ble
2.23e-308 <= |X| <= 1.79e308
lon( 'o*ble
3.37e-4932 <= |X| <= 1.18e4932
Secuencias de escape
Secuencia Carcter Descripcin
\\ 4
6arra inertida
\' ;
Comilla simple #apstro'o$
\" .
Comillas do"les
\? <
Interrogacin
\0 <N=>>>
Cero "inario
\a <52>>
Campana #sonido audi"le$
\b <5?>
7etroceso
\f <11>
%alto de pgina
\n <N>>
%alto de lnea
\r <@A>
7etorno de carro
\t <BC>
/a"ulacin -orizontal
\v </C>
/a"ulacin ertical
Constantes
Nmeros enteros: es posible escribirlos como nmeros decimales, octales (precedidos de 0) o
hexadecimales (precedidos por 0D).
Nmeros de punto flotante: pueden incluir el punto decimal y/o la letra e acompaada de un
nmero entero X, lo cual se interpreta como multiplicar por 10
X
.
Caracteres: deben escribirse entre apstrofos ('').
Cadenas de caracteres: son secuencias de cero o ms caracteres encerrados entre comillas dobles.
Declaradas (const): de modo similar al de las variables, es posible asociar un valor constante, a
un identificador de un tipo determinado:
const <tipo> <constante> = <valor!constante>;
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 6
Por ejemplo:
const double EI " 3.1#;
Definidas (F'e)ine): existe la posibilidad de definir constantes utilizando la directiva de
compilador 'e)ine:
#define <constante> <valor!constante>;
Por ejemplo:
#define MAG 20;
Las constantes definidas de esta forma no tienen tipo lo cual hace que no sea recomendable su
uso y se utilice, siempre que sea posible, constantes declaradas con const.
Tipos de datos compuestos
Adems de los tipos de datos bsicos ya vistos, C++ permite definir tipos de datos llamados compuestos o
estructurados. Esta denominacin se debe a que los tipos de datos compuestos son agrupaciones de otros
tipos de datos.
Dentro de los tipos de datos compuestos se pueden encontrar las enumeraciones, los registros, las
uniones, los arreglos, las cadenas de caracteres, los punteros y la memoria dinmica (esta ltima se ver
en una seccin posterior).

Enumeraciones
Una enumeracin es una lista de valores enteros constantes:
enum <tipo!en*meraci&n> {<constante
1
>, <constante
2
>, ..., constante
n
>};
En la definicin anterior, la primer constante del enum tiene valor 0, la siguiente 1, y as sucesivamente
incrementando de a 1. Tambin pueden especificarse valores explcitos:
enum <tipo!en*meraci&n> {<constante
1
>=<valor!constante>,
<constante
2
>=<valor!constante>, ...};
Por ejemplo:
enum posicion{primero segundo tercero};
Registros
La declaracin de un registro permite agrupar una o ms variables bajo un mismo nombre. Estas variables
pueden ser de cualquier tipo. Para declarar una estructura se utiliza la siguiente sintaxis:
struct <tipo!re(istro>
{
<tipo> <nombre!campo
1
>;
<tipo> <nombre!campo
2
>;
...
<tipo> <nombre!campo
n
>;
};
El identificador del registro puede ser utilizado como el identificador de un nuevo tipo definido, es decir,
para declarar variables del tipo del registro. Por ejemplo, se puede definir una estructura para almacenar
informacin de empleados:
struct 2mplea'o {
int i';
strin( nombre;
strin( apelli'o;
float salario;
};
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 7
Para acceder a los distintos campos que componen una estructura debe emplearse el operador ., del
siguiente modo:
<variable!re(istro>!<nombre!campo>
Por ejemplo:
int main()
{
2mplea'o emp;
emp.i' " 1;
emp.salario " HHH.HH;
emp.nombre " .I*an.;
emp.apelli'o " .EereJ.;
}
Una estructura se puede componer de variables de cualquier tipo de datos, y las estructuras en s, se
utilizan como tipos de datos; por lo tanto, se permite la creacin de estructuras anidadas. Es decir, es
posible definir estructuras donde algunos de sus campos sean, a su vez, otras estructuras. Por ejemplo:
struct ?eccion
{
int i';
strin( nombre;
2mplea'o encar(a'o;
};
Y acceder a los campos, de forma similar:
int main() {
?eccion seccion;
seccion.i' " 1;
seccion.encar(a'o.salario " HHH.HH;
seccion.encar(a'o.nombre " .I*an.;
...
}
Uniones
Las uniones son similares a los registros en la definicin pero difieren en el funcionamiento durante su
utilizacin. Esto se debe a que una unin permite almacenar en la misma porcin de memoria diferentes
tipos de datos. Para declarar una unin se utiliza la siguiente sintaxis:
union <tipo!*nion>
{
<tipo> <nombre!campo
1
>;
<tipo> <nombre!campo
2
>;
...
};
Debido a que todos los elementos de una unin ocupan el mismo espacio de memoria fsica, el tamao de
la unin ser equivalente al tamao del elemento declarado, que ocupa ms lugar. Otra concecuencia de
este funcionamiento es que la modificacin de un elemento llevar a la modificacin de todos los
elementos, a veces con resultados impredecibles.
Por ejemplo, si se define:
union %esc*ento {
int monto;
float porcentaKe;
};
%esc*ento 'esc*ento;
Se podr acceder a 'esc*ento.monto y 'esc*ento.porcentaKe, pero no a ambos elementos al
mismo tiempo. Por lo tanto, generalmente se suele crear un registro con un elemento adicional para
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 8
identificar el elemento que fue almacenado en cada variable, y, de esta forma accederlo, sin
inconvenientes. Por ejemplo:
struct %esc*ento {
c"ar tipo;
union {
int monto;
float porcentaKe;
} meto'o;
};
Luego, para acceder a cada elemento se realizara de la siguiente forma:
%esc*ento 'esc*ento;
'esc*ento.tipo " ;m;;
'esc*ento.meto'o.monto " 10;
Arreglos
Un arreglo es una coleccin de elementos del mismo tipo de datos, que ubica a todos los elementos en
regiones de memoria contigua y a los cuales permite acceder mediante la utilizacin de un ndice.
Para declarar un arreglo se utiliza la siguiente sintaxis:
<tipo> <nombre!arre(lo>#<tamao>$;
El parmetro <tamaLo> debe ser una constante o variable entera positiva que indique el nmero de
elementos mximo que podr contener el arreglo. Por ejemplo para declarar un arreglo de diez enteros:
int arr810:;
Para acceder al valor de una posicin del arreglo se utiliza el operador []:
<nombre!arre(lo>#<Mn'ice>$
Donde 0 = <Mn'ice> <tamaLo>, es decir, los arreglos siempre comienzan en 0, por lo tanto, el
ltimo ndice vlido ser tamaLo N 1.
Este acceso se utilizar tanto para modificar como para obtener el valor almacenado. En cualquiera de los
casos, el resultado del acceso ser equivalente a trabajar con una variable del tipo del arreglo. Por
ejemplo, en el caso siguiente ambos accesos equivalen a una variable de tipo int:
arr82: " 10;
int variable " arr8#:;
Es importante tener en cuenta que no se realiza ninguna verificacin de acceso al arreglo (ni en tiempo de
compilacin ni en tiempo de ejecucin). Es decir, que si se accede a posiciones del arreglo, ms all de las
definidas por su tamao, es muy probable que el programa no termine correctamente su ejecucin a raz
del acceso invlido. Este acceso probablemente resultar en un valor basura (lo cual llevar a errores en
el comportamiento del programa, cuyo origen puede ser difcil de detectar).
Tambin pueden declararse arreglos multidimensionales:
<tipo> <nombre!arre(lo>#<tamao_dim
1
>$#<tamao_dim
2
>$!!!#<tamao_dim
n
>$;
Los arreglos pueden ser inicializados en la misma declaracin como el resto de las variables.
<tipo> <nombre!arre(lo>#<tamao>$ = {<valor
1
> <valor
2
> ... <valor
n
>};
Ejemplos:
c"ar vocales 8-: " {;a; ;e; ;i; ;o; ;*;};
$$Al inicialiJar el arre(lo es posible no 'e)inir s* tamaLo el compila'or lo
tomar3 'e la canti'a' 'e valores.
c"ar vocales 8: " {;a; ;e; ;i; ;o; ;*;};
int matriJ 82:83: " {{ 1 2 3 } { # - O }};
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 9
int matriJ 82:83: " { 1 2 3 # - O };
A los arreglos de dos dimensiones generalmente se los denomina Matrices, ya que es la estructura que se
forma de un arreglo donde cada posicin es, a su vez, otro arreglo.
3os arreglos no estn limitados a dos dimensiones! ya que pueden contener la cantidad de ndices que
sean necesarios #dependiendo de la memoria disponi"le$.
Arreglos como parmetros
En C++ no es posible pasar un bloque completo de memoria como parmetro por valor o copia a una
funcin, pero si es posible pasar su direccin. Por ejemplo, para declarar una funcin que tiene como
argumento un arreglo se debe declarar como sigue:
void imprimir(int arre(lo8:);
Luego se podr invocar mediante:
int valores;
imprimir(valores);
Como se puede ver no se indica el tamao del arreglo que se va a pasar, slo que es un arreglo de
elementos de un tipo de datos determinado (en este caso int). Por lo tanto, cualquier arreglo que respete
el tipo de datos declarado podr ser pasado como parmetro a la funcin. Debido a esto es que,
generalmente, se agrega a las funciones que trabajan con arreglos un segundo parmetro para determinar
el tamao de dicho arreglo.
void imprimir(int arre(lo8: int capaci'a');
Tambin es posible pasar por parmetro un arreglo multidimensional. En estos casos, el tamao de la
primera dimensin no se especifica pero si se debe incluir el tamao de las dems dimensiones en la
declaracin de la funcin, por ejemplo:
void imprimir(int arre(lo8:8#: int capaci'a');
El tamao de la segunda dimensin es necesario para que el compilador determine la capacidad de dicha
dimensin. Debido a esto, la funcin slo podr ser invocada con arreglos multidimensionales cuya
segunda dimensin sea igual a 4.
El pasaje de arreglos, de cualquier dimensin, como parmetros a una funcin plantea una situacin
especial. Debido a que los bloques de memoria contigua no se pueden copiar automticamente, al pasar
un arreglo por copia a una funcin en realidad se est pasando un puntero al arreglo (esto se explicar en
detalle en el apartado de punteros). Por lo tanto, se podrn modificar los valores de los elementos que el
mismo contiene. Por ejemplo, se puede definir la siguiente funcin para cargar valores por defecto a un
arreglo:
void inicialiJar(int arre(lo8: int capaci'a') {
for(int i"0; i < capaci'a'; iPP)
arre(lo8i: " 0;
}
Esta caracterstica de los arreglos! como argumentos de las 'unciones! es algo que -ay que tener muy en
cuenta a la -ora de estructurar los programas ya que puede generar errores inesperados.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 10
Operadores
C++ incorpora el tipo de datos bool, el cual contiene dos literales, )alse y tr*e. Una expresin
booleana o lgica es, por consiguiente, una secuencia de operandos y operadores que se combinan para
producir uno de los valores de verdad posibles: verdadero o falso. C no tiene tipos de datos lgicos o
booleanos para representar los valores verdadero o falso. En su lugar utiliza el tipo int para ese
propsito, con el valor 0 representando falso y cualquier otro valor representando verdadero.
A continuacin se presenta una lista de los operadores ordenados de mayor a menor precedencia:
Nivel de
precedencia
Operadores Descripcin Agrupamiento
1 00 mbito Izquierda a derecha
2
() 8: . Q> PP QQ '+namic!cast
static!cast reinterpret!cast
const!cast t+pei'
Posfijo Izquierda a derecha
3
PP QQ R S siJeo) ne7 'elete Unarios (prefijo)
Derecha a izquierda T U Indireccin y referencia (punteros)
P Q Signo
4 (t+pe) Conversin de tipo Derecha a izquierda
5 .T Q>T Acceso a miembro (punteros) Izquierda a derecha
6 T $ V Multiplicativos Izquierda a derecha
7 P Q Aditivos Izquierda a derecha
8 << >> Desplazamiento Izquierda a derecha
9 < > <" >" Relacionales Izquierda a derecha
10 "" S" Igualdad Izquierda a derecha
11 U AND a nivel de bits Izquierda a derecha
12 W XOR a nivel de bits Izquierda a derecha
13 9 OR a nivel de bits Izquierda a derecha
14 UU AND lgico Izquierda a derecha
15 99 OR lgico Izquierda a derecha
16 <0 Condicional Derecha a izquierda
17
" T" $" V" P" Q" >>" <<" U" W" 9
"
Asignacin Derecha a izquierda
18 Coma Izquierda a derecha
Si dos o ms operadores aparecen en una expresin los mismos se aplican en el orden dado por su
nivel de precedencia.
En el caso que se tenga que resolver operadores del mismo nivel, los operadores se evalan
siguiendo el orden dado por el agrupamiento.
Para forzar un orden especfico para la evaluacin de una expresin se pueden utilizar los
parntesis.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 11
Estructuras de control
Estructuras de seleccin
3as estructuras de seleccin o estructuras condicionales controlan si una sentencia! o secuencia de
sentencias! se ejecutar en 'uncin del cumplimiento o no de una condicin o e+presin lgica. C++ tiene
dos estructuras de control para la seleccin! i) y s7itc6.
Sentencia if
3a sentencia if decide si una sentencia o "loque de cdigo de"e ejecutarse o no en "ase al alor de una o
ms e+presiones lgicas.
if (<eDpresi&n!l&(ica>)
(<sentencia>9<blo,*e>)
{else if (<eDpresi&n!l&(ica>)
(<sentencia>9<blo,*e>)}
8else
(<sentencia>9<blo,*e>):
3as e+presiones lgicas se de'inen entre par&ntesis. 4na sentencia i) puede tener cero o ms sentencias
else i) y opcionalmente una sentencia else. 3as sentencias else y else i) permiten incoporar
decisiones de ejecucin! en "ase a distintos criterios de seleccin. ,or ejemplo)
int b;
cin >> b;
if (b > 10) {
co*t << .2rror0 valor ma+or 'e lo permiti'o.;
} else if (b < 0) {
co*t << .2rror0 valor menor 'e lo permiti'o.;
} else {
procesar/alor(b);
}
Sentencia s%itc"
3a sentencia s%itc" se utiliza para seleccionar una de entre m8ltiples alternatias. Esta sentencia es
especialmente 8til cuando la seleccin se "asa en el alor de una aria"le de un tipo simple o de una
e+presin de un tipo simple! denominada e+presin de control o selector.
s%itc" (<eDpresi&n>) {
case <eDpresi&n!constante> & (<sentencia>9<blo,*e>); brea';
{case <eDpresi&n!constante> &} (<sentencia>9<blo,*e>); brea';
8default & (<sentencia>9<blo,*e>) ; brea';:
}
4na sentencia s7itc6 puede tener una o ms sentencias case y opcionalmente una sentencia 'eQ
)a*lt. /odas las e+presiones de"en terminar con el comando breaX! de esta 'orma se eita que se ea9
l8e la condicin siguiente.
,or ejemplo)
int opcion;
cin >> opcion;
s%itc" (opcion) {
case 10
co*t << .Ypci&n 1.;
brea';
case 20
case 30
co*t << .Ypci&n 2 o 3.;
brea';
default0 {
co*t << .Ypci&n invali'a4n. << .In(rese *na n*eva opci&n.;
} brea';
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 12
Estructuras de iteracin
Las sentencias de iteracin permiten repetir un conjunto de sentencias un nmero determinado de veces.
Sentencia %"ile
4n ciclo %"ile tiene una condicin de control o e+presin lgica que controla la repeticin de la
ejecucin de una secuencia de sentencias.
%"ile (<eDpresi&n!l&(ica>)
(<sentencia> 9 <blo,*e>)
El cuerpo del ciclo se ejecuta mientras la expresin lgica sea cierta.
Por ejemplo:
int cont " 0;
%"ile (cont <" 20) {
co*t << ./alor 'el conta'or0 . << cont << .4n.;
contPP;
}
Sentencia do(%"ile
La sentencia do(%"ile se utiliza para definir un bucle en el que la condicin de terminacin se evaluar
al final del ciclo.
do
(<sentencia>9<blo,*e>)
%"ile (<eDpresi&n!l&(ica>);
3a e+presin lgica se comprue"a despu&s de la ejecucin del cuerpo del ciclo.
Por ejemplo:
int cont " 0;
do {
co*t << ./alor 'el conta'or0 . << cont << .4n.;
contPP;
} %"ile (cont <" 20);
El resultado de este ejemplo es similar al ejemplo anterior para el %"ile! pero la di'erencia reside en que
el cuerpo de una sentencia doQ%"ile siempre se ejecuta al menos una ez.
Sentencia for
En general, la sentencia for se utiliza para definir un ciclo en el que una variable se incrementa o
decrementa de manera constante en cada iteracin y la finalizacin del ciclo se determina mediante una
expresin que involucra dicha variable.
for (<inicialiJacion>; <eDpresi&n!l&(ica>; <incremento>)
(<sentencia>9<blo,*e>)
donde en <inicialiJacion> se inicializa la aria"le de control del "ucle. El cuerpo del ciclo se ejecuta
mientras la e+presin lgica sea cierta.
Por ejemplo:
for (int cont " 0; cont <" 20; contPP) {
co*t << ./alor 'el conta'or0 . << cont << .4n.;
}
<inicialiJacion>, <eDpresi&n!l&(ica> e <incremento> pueden omitirse, manteniendo los punto y
coma.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 13
Funciones
Una funcin es un bloque de cdigo dentro de un programa, que posee las siguientes caractersticas:
tiene un nombre que la identifica;
puede retornar un resultado, llamado valor de retorno (cuyo tipo es el correspondiente al tipo de
retorno); y,
puede tener parmetros, que actan como variables locales al bloque del cuerpo de la funcin.
Las funciones son ejecutadas a travs de su invocacin o llamado, para lo cual se escribe su nombre y
entre parntesis la lista de argumentos, los cuales son utilizados para inicializar los parmetros
correspondientes. Al llamar a una funcin el control de ejecucin del programa pasa al bloque de
sentencias de la misma; hasta que se llega al final del bloque o se devuelve un valor, luego de lo cual el
control vuelve a la funcin que realiz la llamada. Una funcin puede ser llamada por s misma -un
llamado recursivo- o por otras funciones.
Mediante el uso de funciones se pueden modularizar los programas, lo cual permite mejorar su estructura
y evitar la duplicacin de cdigo, obteniendo un cdigo ms legible y fcil de mantener.
Declaracin
La declaracin de las funciones (tambin llamado prototipado de funciones) indica al compilador la
existencia de las mismas y es necesaria antes de poder utilizarlas. La declaracin incluye el nombre de la
funcin, la lista de parmetros y el tipo de valor de retorno:
<tipo!retorno> <nombre!)*nci&n>(<lista!'e!par3metros>);$$;para )inaliJar la
'eclaraci&n
Debido a que en C++ todos los procedimientos son funciones, para indicar que una funcin no devuelve
un valor se utiliza el tipo especial void, que indica la ausencia de valor. El tipo de valor de retorno puede
ser cualquier tipo de datos excepto arreglos.
La lista de parmetros es una lista de declaraciones de objetos o referencias separadas por comas. En
algunos casos, cuando se est definiendo un prototipo de una funcin, la lista de parmetros slo incluye
los tipos de los parmetros sin los nombres. La lista de parmetros tambin puede estar vaca lo que
indica que la funcin no toma parmetros.
Una funcin puede ser declarada ms de una vez en un mismo programa.
Definicin
La definicin de una funcin incluye el nombre, la lista de parmetros, el tipo de valor de retorno y el
bloque de sentencias que constituyen el cuerpo de la funcin. La definicin de las funciones completa la
especificacin de las mismas.
Es necesario que todas las funciones utilizadas cuenten con una definicin para que el proceso de
construccin del programa finalice con xito. A diferencia de las declaraciones, slo debe haber una nica
definicin para cada funcin. Es ms, las funciones pueden definirse sin necesidad de declararlas
previamente, ya que el encabezado de la definicin contiene la misma informacin que la declaracin
(nombre, cantidad y tipo de los parmetros y el tipo de retorno).
El formato de una definicin es el siguiente:
<tipo!retorno> <nombre!)*nci&n>(<lista!'e!par3metros>)
{
<sentencias>
}
Todas las funciones cuyo tipo de retorno no es voi' deben retornar un valor. El valor de retorno se
especifica utilizando una sentencia con la palabra clave ret*rn:
ret*rn <eDpresi&n>;
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 14
El valor de la expresin debe coincidir con el valor del tipo de retorno. Cuando se llega a una sentencia
ret*rn el control de la ejecucin retorna a la funcin que realiz el llamado. Debido a esto, no se
ejecutar cdigo ubicado por debajo de la sentencia ret*rn.
Puede haber ms de una sentencia ret*rn y las mismas pueden ubicarse en cualquier parte del cdigo.
Es importante asegurar que en todos los casos de ejecucin posibles se devolver un valor, es por eso que
se recomienda que las sentencias ret*rn sean las mnimas indispensables y que se las ubique sobre el
final del cuerpo de la funcin.
Ejemplos:
$$ %eclaraci&n 'e la )*nci&n obtenerErome'io
float obtener)romedio(int enteros8: int canti'a');
$$ %e)inici&n 'irecta 'e la )*nci&n imprimir2nteros
void im*rimir+nteros(int enteros8: int canti'a')
{
for (int i " 0; i < canti'a'; iPP) {
co*t << ./alor . << i << .0 . << enteros8i: << .4n.;
}
}
const int N " 10;
int main()
{
int arr8N: " {23-123###-23--HH0};
imprimir2nteros(arr N);
$T ?e p*e'e *tiliJar la )*nci&n obtenerErome'io a*n,*e no se 6a+a
especi)ica'o completamente +a ,*e para realiJar el llama'o es
s*)iciente con la in)ormaci&n provista por la 'eclaraci&n T$
co*t << obtenerErome'io(arr N) << .4n.;
return 0;
}
$$ %e)inici&n 'e )*nci&n obtenerErome'io 'eclara'a anteriormente
float obtener)romedio(int enteros8: int canti'a')
{
float s*ma " 0;
for (int i " 0; i < canti'a'; iPP) {
s*ma " s*ma P enteros8i:;
}
return s*ma $ canti'a';
}
Pasaje de parmetros
La declaracin de los parmetros permite indicar si los mismos estarn relacionados con los argumentos a
travs de la copia o la referencia.
El pasaje de argumentos por valor o copia se especifica a travs de tipos comunes:
<tipo> <par3metro>
El pasaje de argumentos por referencia se especifica a travs de tipos de referencia (utilizando el
declarador de referencia U luego del tipo):
<tipo> , <par3metro>
En el caso del pasaje por valor, cada parmetro es un objeto local a la funcin, que es inicializado con el
valor del argumento durante su creacin, pero luego de eso opera en forma independiente. Esto significa
que los cambios en el valor de los parmetros no afectarn al valor de los argumentos al momento de
finalizar la ejecucin de la funcin.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 15
Por otra parte, los parmetros que son referencias constituyen un alias a los objetos utilizados como
argumentos. Durante el pasaje de parmetros por referencia no se crean nuevos objetos ni ocurre ningn
tipo de duplicacin de los argumentos, sino que las referencias son inicializadas para operar directamente
sobre estos argumentos. De esta forma los parmetros de referencia quedan vinculados a los argumentos y
todas las operaciones que modifiquen su estado se vern reflejadas en el valor de los mismos cuando
termine la ejecucin de la funcin.
Ejemplo de pasaje de argumentos por copia:
void modificar (int variable)
{
variable " 10;
co*t << .mo'i)icar N valor variable0 . << variable << .4n.;
}
int main()
{
int variable " 2;
mo'i)icar(variable);
co*t << .main N valor variable0 . << variable << .4n.;
}
La salida es la siguiente:
> mo'i)icar N valor variable0 10
> main N valor variable0 2
Ejemplo de pasaje de argumentos por referencia:
void modificar(int , variable)
{
variable " 10;
co*t << .mo'i)icar N valor variable0 . << variable << .4n.;
}
int main()
{
int variable " 2;
mo'i)icar(variable);
co*t << .main N valor variable0 . << variable << .4n.;
}
La salida es la siguiente:
> mo'i)icar N valor variable0 10
> main N valor variable0 10
%e puede utilizar el pasaje de argumentos por re'erencia cuando es necesario que una 'uncin retorne ms
de un alor! ya que las 'unciones permiten un 8nico alor de retorno.
El pasaje de argumentos por re'erencia es una mecanismo introducido en C++. C slo permite el pasaje
por alor o copia* por lo tanto! para que una 'uncin modi'ique el alor de un argumento se de"en utilizar
punteros #lo cual se e re'lejado en muc-as de las declaraciones de la "i"lioteca estndar de C$. %in
em"argo! para programas escritos en C++ se recomienda utilizar el pasaje de parmetros por re'erencia y
slo utilizar punteros cuando sea realmente necesario.
Sobrecarga de funciones
Las funciones pueden tener el mismo nombre y valor de retorno pero con distintos tipos y cantidad de
parmetros. El compilador determinar a qu funcin invocar examinando los argumentos y buscando una
lista de parmetros que se ajuste a los mismos entre las funciones candidatas.
Por ejemplo:
float o*erar(int D int +) {...}
float o*erar(float D float +) {...}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 16
Una funcin no puede ser sobrecargada slo retornando diferentes tipos. Al menos uno de sus parmetros
debe tener un tipo diferente.
Funciones recursivas
Se dice que una funcin es recursiva cuando se define en funcin de s misma, es decir, en algn
momento de su definicin se encuentra una llamada a la misma funcin que se est definiendo. Existen
dos tipos de recursin:
1. Directa: cuando una funcin se llama a s misma.
2. Indirecta: cuando una funcin invoca a una segunda funcin y esta, a su vez, llama a la primera
funcin.
La recursividad es un tcnica elemental de programacin que no todos los lenguajes permiten utilizar.
C++ soporta la recursividad, para esto, cada vez que se llama a una funcin, se crea un juego de variables
locales. Si la funcin hace una llamada a s misma, se guardan sus variables y parmetros en la pila, y la
nueva instancia de la funcin trabajar con su propia copia de las variables locales. Cuando esta segunda
instancia de la funcin retorna, recupera las variables y los parmetros de la pila y continua la ejecucin
en el punto en que haba sido llamada.
Una funcin recursiva puede dar origen a un problema muy comn en programacin, la recursin infinita,
que es un error generado por una funcin que se llama a s misma infinitas veces. Para que esto no suceda
una funcin recursiva debe saber resolver el caso ms simple, llamado caso base. Si la funcin es llamada
con el caso base, inmediatamente retorna el resultado (no necesita volver a llamarse a s misma para
poder resolverlo). Si la funcin es llamada con un caso ms complejo, las sucesivas llamadas a s mismas
irn virtualmente descomponiendo ese caso hasta llegar a un caso base, para luego determinar el resultado
final de la funcin. A partir de esto se puede esquematizar a una funcin recursiva mediante el siguiente
cdigo:
<tipo!retorno> <nombre!)*nci&n>(<lista!'e!par3metros>)
{
si <con'ici&n!caso!base>
ret*rn <valor!base>
sino
<sentencias>
ret*rn <nombre!)*nci&n>
}
Por ejemplo, para calcular el factorial de un nmero (n! = n * (n 1)!) se puede definir la siguiente
funcin recursiva:
int factorial(int n*mero) {
if (n*mero "" 0)
return 1;
else
return (n*mero T )actorial(n*meroQ1));
}
Comparacin entre iteracin y recursin
La recursin es una forma de iteracin, sin embargo, existen diferencias que son importantes resaltar. La
iteracin consiste en la repeticin de sentencias hasta que se cumple cierta condicin que marca la
detencin del proceso. Si se llama a funciones durante una funcin iterativa, estas funciones se iniciarn y
detendrn en cada ciclo de la iteracin. En cambio, en las funciones recursivas, en cada ciclo recursivo se
inicia la llamada a una funcin recursiva, pero no su detencin, dado que la funcin se est invocando a s
misma hasta alcanzar la condicin del caso base.
La recursividad permite resolver problemas quizs de forma ms simple que mediante funciones
iterativas; incluso, hay problemas que inherentemente requieren una solucin mediante esta tcnica por
sus caractersticas. Sin embargo, esta tcnica generalmente trae un costo asociado en el consumo de
memoria dado que se reserva memoria para todas las variables usadas por la funcin, tantas veces como
dicha funcin sea invocada.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 17
Argumentos de los programas
La funcin main puede definirse con o sin parmetros. Para que incluya parmetros se suele definir de la
siguiente forma:
int main(int ar(c c"ar T ar(v8:)
argc : indica el nmero de los argumentos que se utilizaron al ejecutar el programa.
argv : contiene cada una de las cadenas de caracteres que constituyen esos argumentos.
Al ejecutar cualquier programa siempre se pasa como primer argumento el nombre del mismo.
Un pequeo programa que muestra cmo acceder a los argumentos es el siguiente:
int main(int ar(c c"ar T ar(v8:)
{
co*t << .@anti'a' 'e ar(*mentos0 . << ar(c << .4n.);
co*t << .Ar(*mentos0 .;
for (int i " 0; i < ar(c; iPP)
co*t << ar(v8i: << . .;
return 0;
}
Un ejemplo de una ejecucin del programa anterior (desde la lnea de comandos):
>eKemplo ar(1 ar(2 ar(3
>@anti'a' 'e ar(*mentos0 #
>Ar(*mentos0 eKemplo ar(1 ar(2 ar(3
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 18
Bibliotecas
Al igual que otros lenguajes de programacin! C++ proee un mecanismo para -acer uso de "i"liotecas
durante el desarrollo de aplicaciones. 4na "i"lioteca es un conjunto de cdigo y datos 8tiles que "rindan
sericios a programas independientes. ,or ejemplo! -ay "i"liotecas para el manejo de entrada y salida de
datos por consola! para el di"ujo de gr'icos en :D y ;D e inter'aces de usuario! para el manejo de
matrices y 'unciones matemticas aanzadas! entre otras utilidades.
Cuando se desarrolla una aplicacin en C++, se cuenta con la biblioteca estndar de C y con la
biblioteca estndar de C++. Ambas bibliotecas proveen un conjunto de funcionalidad bsica como, por
ejemplo, funciones para realizar operaciones matemticas, manejar cadenas de caracteres, realizar entrada
y salida de datos a travs de archivos y la consola, etc. Sin la biblioteca estndar los programas se veran
muy restringidos en utilidad, ya que no se podra realizar ninguna de las funciones bsicas mencionadas
anteriormente.
Para incluir una biblioteca se utiliza la directiva del compilador include. Por ejemplo, para extender el
programa mnimo e imprimir un mensaje por pantalla, se puede utilizar:
La biblioteca de streams de entrada/salida de C++ iostream, la cual provee el objeto co*t que
cuenta con el operador <<:
#include <iostream>
int main()
{
st'00co*t << .Bola M*n'oS.;
return 0;
}
La biblioteca estndar de C que tambin incluye funciones para entrada y salida de datos. Por lo
tanto, es posible utilizarla para escribir un programa equivalente al anterior, empleando la
biblioteca cst'io y la funcin print):
#include <cst'io>
int main() {
print)(.Bola M*n'oS.);
return 0;
}
Directiva include
E+isten dos 'ormas para especi'icar el nom"re de la "i"liteca que ser incluida! la 8nica di'erencia es el
conjunto de directorios en donde el compilador "uscar el arc-io indicado)
#include .arc6ivo.
Si se especifica el archivo entre comillas dobles, primero se buscar el archivo en el
mismo directorio en el que se encuentra el archivo fuente que contiene la directiva. Si el
archivo no se encuentra ah el compilador lo busca en los directorios configurados por
defecto para buscar los archivos de cabecera estndar.
#include <arc6ivo>
Si el nombre del archivo se encierra entre llaves angulares el archivo se busca
directamente en los directorios configurados por defecto del compilador.
Espacios de nombres
Los espacios de nombres (namespaces) permiten estructurar los programas en unidades lgicas. Cada una
de estas unidades puede contener tipos, funciones y objetos agrupados bajo un nombre comn.
Separando las funciones en espacios de nombres diferentes se evita que se utilicen los mismos
identificadores para definir distintas entidades, dentro del cdigo de un programa y en las bibliotecas que
se utilizan.
Existen dos formas de indicar que se va a utilizar una entidad que pertenece a un espacio de nombres
determinado:
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 19
Especificar en cada referencia a la entidad a qu espacio de nombres pertenece. Esto se consigue
utilizando el operador de mbito 00, y anteponiendo el nombre del espacio al nombre del
elemento:
<espacio!nombres>&&<tipo9)*nci&n9obKeto>
Indicarle al compilador que en una regin declarativa se utilizarn entidades pertenecientes a un
espacio de nombres determinado, mediante las palabras clave *sin( namespace)
using names*ace <espacio!nombres>;
A continuacin se presenta un ejemplo utilizando el objeto co*t, que forma parte de la biblioteca
estndar de C++, la cual declara todas sus entidades dentro del espacio de nombres std.
Alternativa 1 Alternativa 2
#include <iostream>
int main() {
st'00co*t << .Bola M*n'oS.;
return 0;
}
#include <iostream>
using names*ace st';
int main() {
co*t << .Bola M*n'oS.;
return 0;
}
Bibliotecas para las funciones ms comunes
La tabla siguiente muestra muy resumidamente los encabezados y funciones/objetos de las bibliotecas
estndar de C y C++ para tarea bsicas, como la entrada y salida de datos por consola, el manejo de
archivos y el manejo de cadenas:
Funciones para C C++
Entrada/Salida por
consola
cstdio0
scan) print) )(ets ...
iostream0
cin co*t (etline ...
Manejo de Cadenas
cstring0
strcp+ strlen strcat ...
string0
strin( (P siJe c!str ...)
Manejo de archivos
cstdio0
)open )print) )7rite ...
fstream0
)stream (open >> << ...)
Por convencin, cuando se incluye una parte de la biblioteca estndar de C en un programa escrito en
C++, se agrega delante del nombre de la biblioteca la letra c y no se escribe la extensin .h.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 20
Manejo de entrada/salida por consola
Manejo de la consola en C++
Al incluir el encabezado iostream, se dispondr del objeto cin para realizar operaciones de entrada,
del objeto cout para operaciones salida, y de un conjunto de operadores para interactuar con dichos
objetos. A continuacin se detalla la forma de uso y operaciones ms comunes de cada uno.
Salida por consola
Para esto se utiliza el operador del objeto co*t; este objeto emite por pantalla el valor de una variable
o constante de cualquier tipo de dato estndar de C++ (caracteres, cadenas, nmeros enteros o reales,
etc.), y tambin movimientos especiales del cursor (por ejemplo, 4n o 4t).
La sintaxis es la siguiente:
co*t << var; co*t << cte;
co*t << var
1
<< var
2
<< ... << var
n
; co*t << cte
1
<< cte
2
<< ... << cte
n
;
co*t << var
1
<< cte
1
<< var
2
<< cte
2
<< ... << var
n
<< cte
n
;
Por ejemplo:
int n*m " -12;
co*t << .2l valor 'el nZmero es0 . << n*m << .4n.;
Como se ve, no se indica el tipo de variable que se va a imprimir, por lo tanto, es el sistema el que
determina el tipo de variable y la forma ms adecuada de imprimirlo.
Entrada por consola
Mediante el operador -- del objeto cin, se puede leer, con formato, los valores de variables numricas
(int, lon(, )loat, 'o*ble, etc), caracteres (c6ar) y cadenas de caracteres (strin( y c6arT). Al
decir con formato, se hace referencia al hecho de que se aplicarn las transformaciones necesarias para
convertir la cadena de caracteres ingresada por la consola, al tipo de la variable pasada como parmetro.
La sintaxis es la siguiente:
cin >> var;
cin >> var1 >> var2 >> ... >> varn;
Al ingresar el texto por la consola se utilizarn los espacios y retornos de lnea como separadores. Por
ejemplo:
int n*m1 n*m2;
string ca'ena;
cin >> n*m1 >> n*m2 >> ca'ena;
Cuando se ejecuta este cdigo, al llegar a la lnea de cin, se pedir el ingreso de los valores para n*m1,
n*m2 y ca'ena. Si se ingresa lo siguiente:
> 123 #-O 6ola
los valores que se asignarn son:
n*m1 [ 123
n*m2 [ #-O
ca'ena [ 6ola
Sincronizacin de la entrada
Si se utilizan espacios como separadores, se intentar asignar cada parte de la cadena de entrada a una
variable. De no ser posible, al no haber suficientes variables en los parmetros de cin, el resto de la
entrada no asignada ser guardada por el objeto cin. Como consecuencia, la prxima vez que se invoque
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 21
a cin >> se intentar asignar el resto de la entrada guardada previamente.
Por ejemplo:
string ca'1 ca'2;
cin >> ca'1; Se ingresa hola mundo!. Se asigna hola a cad1.
co*t << ca'1 << ;4n;; Se imprime hola.
cin >> ca'2; Se asigna automticamente mundo! a cad2.
co*t << ca'2 << ;4n;; Se imprime mundo!.
Para evitar este comportamiento se debe utilizar el comando cin.i(nore()
-
. El mismo descarta un
cierto nmero de caracteres de la secuencia de entrada o bien descarta todo lo que se encuentre hasta un
carcter delimitador. Para corregir el ejemplo anterior es conveniente construir una funcin que utilice el
mtodo cin.i(nore() de modo que descarte todo lo que se encuentra hasta el final de la lnea:
#include <iostream>
#include <limits>
void ignorar.inea() {
cin.i(nore(n*meric!limits<st'00streamsiJe>00max() ;4n;);
}
Una vez definida se puede utilizar la funcin antes o despus de cada operacin de lectura sobre cin:
string ca'1 ca'2;
cin >> ca'1; Se ingresa hola mundo!. Se asigna hola a cad1.
co*t << ca'1 << ;4n;; Se imprime hola.
i(norar>inea(); Se vaca la secuencia de entrada.
cin >> ca'2; Se ingresa otra cadena. Se asigna otra a cad2.
co*t << ca'2 << ;4n;; Se imprime otra.
i(norar>inea(); Se vaca la secuencia de entrada.
Leer lneas completas
Existen dos formas de leer lneas completas a travs de cin. La primer opcin es utilizar la funcin
(etline() provista por la biblioteca strin(, la cual carga una lnea desde cin a una cadena del tipo
strin(. La segunda opcin es utilizar el mtodo cin.(etline(), que realiza la misma funcin pero
trabaja con cadenas de caracteres del tipo c6arT.
(etline(): mediante este mtodo se pude leer desde cualquier stream de entrada una lnea
completa hasta el fin de lnea u otro carcter que se indique. La definicin de (etline() es la
siguiente:
istreamU getline(istreamU is strin(U str)
istreamU getline(istreamU is strin(U str c"ar 'elim)
is es el stream de entrada del cual se extraer la lnea. Generalmente se utilizar el objeto
cin como parmetro, pero tambin es posible usar un stream de entrada asociado a un
archivo de texto, por ejemplo.
str es la cadena de caracteres donde se escribir la lnea leda desde is;
delim es el separador que se utilizar. Cuando no se especifica el separador por defecto
ser el retorno de lnea.
5
A veces se propone utilizar cin.s+nc(), pero esta solucin es dependiente de la plataforma que se est utilizando ya
que, en general, no se garantiza que dicha funcin descartar los caracteres no ledos de la secuencia de entrada. Es por eso
que se recomienda utilizar cin.i(nore() para dicha tarea.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 22
cin.(etline(): mediante este mtodo se lee desde la consola una lnea completa hasta el fin
de lnea u otro carcter que se indique. La definicin de cin.(etline() es la siguiente:
istreamU istream&&getline(c"arT str streamsiJe n);
istreamU istream&&getline(c"arT str streamsiJe n c"ar 'elimita'or);
str debe ser una cadena de caracteres de un tamao mayor o igual a n;
n ser la cantidad mxima de caracteres de la lnea que se escribirn en cadena
(incluyendo el carcter nulo);
delim es el separador que se utilizar. Cuando no se especifica el separador por defecto
ser el retorno de lnea.
/anto (etline() como cin.(etline() leern la lnea hasta encontrar el separador. En el caso de
cin.(etline() se leer hasta almacenar la cantidad mxima de caracteres indicada si no se encuentra
el delimitador antes. El separador es extrado de la entrada pero no se asigna a la cadena de destino.
Para usar sin inconvenientes cualquiera de las dos funciones (en particular cin.(etline()) junto con
el operador >> de cin, es necesario llamar a cin.i(nore() antes de intentar leer una lnea completa.
Esto se debe a que luego de utilizar el operador >>, queda guardado en cin un separador sin asignar.
Por ejemplo:
string ca' linea;
cin >> ca';
i(norar>inea();
(etline(cin linea);
co*t << ca' << ;4n;;
co*t << linea << ;4n;;
Configuracin del formato de la entrada y la salida
Tanto cin como co*t cuentan con una serie de mtodos que permiten definir ciertos parmetros del
formato del texto que se leer o escribir:
fmtflags flags(fmtflags )mt)l);
Permite cambiar a travs de flags la forma en que se interpreta la
entrada o se muestra la salida
6
.
streamsi/e *recision(streamsi/e prec);
Especifica cuntos dgitos se mostrarn luego del punto decimal.
streamsi/e %idt"(streamsi/e 7i'e);
Especifica el nmero mnimo de caracteres que se mostrar al
escribir un valor. Si la representacin del valor de salida es menor
que el ancho del campo de salida el mismo se completar con
caracteres de relleno (espacios por defecto).
Manejo de la consola en C
Las funciones para entrada y salida por consola de la biblioteca de C se encuentran definidas en el
encabezado cstdio.
La principal diferencia que existe al realizar entrada/salida por consola en C, es que las funciones que se
utilizan para esto necesitan que se especifique el tipo de valor de la variable que se imprimir o cargar
por consola. Esta informacin se indica a travs de una cadena de formato, la cual contiene dos tipos de
objetos: caracteres ordinarios, que son copiados textualmente a la salida y especificaciones de
conversin, cada uno de los cuales causa la conversin de los argumentos sucesivos. Cada especificacin
de conversin comienza con un 0 y termina con un carcter de conversin. Entre el V y el carcter de
conversin puede haber otros indicadores
7
.
6
Para acceder la lista completa de flags ver: http://www.cplusplus.com/reference/iostream/ios_base/fmtflags.html
7
Para ver la lista completa de caracteres de conversin y el resto de los especificadores de la cadena de formato ver:
http://www.cplusplus.com/reference/clibrary/cstdio/printf.html
http://cplusplus.com/reference/clibrary/cstdio/fscanf.html
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 23
Caracteres de conversin (lista parcial) Significado
' i
Entero decimal
) e 2 ( \
Punto flotante
6
Entero corto
c
Carcter
s
Cadena de caracteres (c6arT)
Salida por consola
Para imprimir datos en la consola se utiliza la funcin *rintf:
int *rintf(const c"ar T )ormat ...)
Esta funcin convierte, da formato e imprime sus argumentos en la salida estndar, de acuerdo a las
especificaciones de conversin que se pueden encontrar en la cadena de formato. En el siguiente ejemplo,
se puede ver que cada uno de los valores de las variables deber ser convertido en un valor entero
decimal.
int 'ia " 1 mes " 1 aLo " 1HHH;
print)(.V'$V'$V'. 'ia mes aLo);
Entrada por consola
Para leer valores ingresados desde la consola se utiliza la funcin scanf:
int scanf(const c"ar T )ormat ...);
Esta funcin lee caracteres de la entrada estndar, los interpreta de acuerdo con las especificaciones que
estn en la cadena de formato, y almacena los resultados a travs de los argumentos restantes, donde cada
uno de estos argumentos debe ser una referencia
8
.
Por ejemplo, se pueden leer fechas ingresadas desde la entrada con el formato <int=/<int=/<int=,
mediante la utilizacin de scan) como sigue:
int 'ia mes aLo;
scan)(.V'$V'$V'. U'ia Umes UaLo);
Manejo de cadenas
Cadenas de C++
Para el manejo de cadenas de caracteres C++ agrega una clase llamada strin(, la cual se encuentra
definida en la biblioteca strin(. Las principales ventajas de esta representacin de las cadenas de
caracteres son el carcter dinmico del tamao de las mismas, y la posibilidad de realizar muchas de las
funciones ms comunes, como la comparacin y la concatenacin, utilizando los operadores clsicos (==,
!=, >, <, +, etc). Adems, las cadenas de C++ pueden ser indexadas para acceder a cada carcter en forma
individual utilizando el operador [] (como si fuesen arreglos comunes).
Otra ventaja es la integracin de la clase strin( con los streams de entrada/salida (por consola y
archivos), por ejemplo:
string ca'ena;
cin >> ca'ena;
co*t << ca'ena;
(etline(cin ca'ena);
co*t << ca'ena;
8
Ver la seccin de Punteros y manejo de memoria.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 24
Por ejemplo:
for(int i " 0; i < ca'ena.len(t6(); iPP) {
co*t << ca'ena8i:;
}
Algunas 'unciones 8tiles de la clase strin(
H
)
siJe!t leng"t() const;
siJe!t si/e() const;
Deuele el n8mero de caracteres de la cadena.
siJe!t find(const strin(U patron siJe!t
posicion " 0) const;
siJe!t find(const c"arU patron siJe!t
posicion " 0) const;
siJe!t find(c"ar c siJe!t posicion " 0)
const;
Deuele la posicin de la primer ocurrencia del patrn o
el alor especial npos si no es encontrado. El parmetro
de la posicin puede utilizarse para indicar a partir de qu&
lugar de"e empezar la "8squeda! pero el mismo puede
omitirse.
strin( substr(siJe!t posicion " 0
siJe!t lon(it*' " npos) const;
Deuele una su"cadena de acuerdo a los alores enteros
pasados.
const c"arT c1str() const;
Deuele el alor del string como una cadena C
terminada por el carcter nulo.
Cadenas de C
En C las cadenas de caracteres se representan a partir de arreglos de caracteres (tambin llamados c-
string). As, se puede definir una cadena de caracteres que permita almacenar hasta 50 caracteres
mediante:
c"ar ca'ena8-0:;
Debido a que el arreglo de caracteres puede almacenar cadenas de longitud menor a 50, es necesario
contar con algn carcter especial que determine el fin de dicha cadena. Para esto se utiliza el carcter
nulo '\0'. Si el arreglo no incluye este carcter al final no se considerar como una cadena de caracteres,
sino como un simple arreglo de caracteres. Esto es muy importante, principalmente cuando se utilizan las
funciones que define la biblioteca estndar de C para trabajar con cadenas.
4n error muy 'recuente es intentar copiar con el operador de asignacin #ca'ena1 " ca'ena2$. Esto
no es lido! de"ido a que no est permitida la copia por asignacin de arreglos #o "loques de memoria$.
Inicializacin de las cadenas de caracteres
Al igual que los arreglos de otros tipos de datos, las cadenas de caracteres pueden ser inicializadas
durante su declaracin.
c"ar palabra 8-: " {;B; ;o; ;l; ;a; ;40;};
c"ar palabra 8: " {;B; ;o; ;l; ;a; ;40;};
Como se puede ver, el ltimo carcter debe ser utilizado para almacenar el carcter nulo, por lo tanto, si el
tamao del arreglo es n, el espacio disponible para caracteres significativos ser n-1.
Pero las cadenas de caracteres tambin pueden ser inicializados mediante el uso de cadenas literales, es
decir:
c"ar ca'ena8: " .Bola.;
En este ltimo caso no es necesario agregar el carcter '40', ya que se aade por defecto a todos las
cadenas de literales. El arreglo resultante tendr un tamao de 5 caracteres (4 caracteres de la palabra ms
el carcter nulo).
Para cargar una cadena de caracteres por posicin, se puede realizar lo siguiente:
c"ar ca'ena820:;
ca'ena80: " ;a;;
ca'ena81: " ;b;;
ca'ena82: " ;40;;
9
Para ver la lista completa de mtodos de la clase strin( visitar: http://www.cplusplus.com/reference/string/string/
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 25
Adems de los arreglos, tambin es posible utilizar cualquier secuencia de caracteres para representar las
cadenas de C. Es por esto que el tipo asociado a las cadenas es un puntero a un bloque de caracteres,
c6arT, donde el valor del mismo indica la posicin del primer carcter. Una ltima consideracin
respecto a lo anterior es que utilizando esta definicin para un parmetro, si bien no se podr modificar a
la variable para que referencie a otra cadena, an ser posible modificar su contenido. Es por eso que para
los parmetros que presenten referencias a cadenas de slo lectura se deber utilizar la definicin const
c6arT.
Operaciones de entrada/salida por consola
Para mostrar una cadena de caracteres, se puede utilizar:
co*t << ca'ena;
o bien
print)(.Vs. ca'ena);
Ambas funciones mostrarn todos los caracteres situados a partir de la direccin de inicio hasta
encuentrar el carcter '40', el cual no se imprime.
Para leer una cadena de C desde la consola hay que considerar el carcter esttico de las secuencias de
caracteres utilizadas para implementarlos. Esta situacin representa una complicacin (respecto a los
strings de C++ que son dinmicos) ya que el procedimiento de lectura podra sobrepasar su capacidad
durante la carga. Es por eso que se recomienda indicar siempre el tamao del arreglo a las funciones de
lectura. Por ejemplo:
cin.(etline(ca'ena 20);
Tambin se puede definir el nmero mximo de caracteres a leer a travs del indicador de ancho de la
cadena de formato de scan)() 0#anc"o$#ti*o$ o bien utilizar la funcin )(ets():
scan)(.V20s. ca'ena);
)(ets(ca'ena 20 st'in); $$ 1*nci&n 'e)ini'a en la biblioteca cst'io
Funciones para el manejo de cadenas
3a "i"lioteca de cstrin( proporciona muc-as 'unciones 8tiles para el manejo de cadenas de C! como la
comparacin! copia! concatenacin y "8squeda de cadenas)
int strcm*(const c"ar T str1 const
c"ar T str2 si/e1t n*m);
Compara hasta n*m caracteres de las cadenas str1 y str2.
Devuelve un valor entero indicando la relacin entre las cadenas:
negativo indica que str1 es menor que str2
cero indica que las cadenas son iguales
positivo indica que str1 es mayor a str2
c"ar T strcat(c"ar T 'est const
c"ar T src siJe!t n*m);
Aade los primeros n*m caracteres de la cadena src al final de la
cadena 'est incluyendo un carcter nulo para la terminacin. Se supone
que la cadena de destino es lo suficientemente grande para contener el
resultado.
c"ar T strc*2(c"ar T 'est const
c"ar T src siJe!t n*m);
Copia los primeros n*m caracteres de la cadena src en la cadena 'est
incluyendo un carcter nulo para la terminacin. Si n*m es mayor a la
longitud de src se escribir en dest una cantidad de ceros igual a la
diferencia.
siJe!t strlen(const c"ar T s);
Devuelve la longitud de la cadena, menos el carcter de terminacin.
c"ar T strcm*(c"ar T str1 const
c"ar T str2
Devuelve un puntero a la primera posicin de la ocurrencia de str2 en
str1, o un puntero nulo en el caso de que str2 no sea parte de str1.
A su vez, la biblioteca cstlib cuenta con funciones para realizar conversiones de cadenas a nmeros:
int atoi(const c"ar T str);
Interpreta el contenido de la cadena str como si fuese un nmero entero
y retorna su valor como int.
long int atoi(const c"ar T str);
Interpreta el contenido de la cadena str como si fuese un nmero entero
y retorna su valor como lon( int.
double atof(const c"ar T str);
Interpreta el contenido de la cadena str como si fuese un nmero de
punto flotante y retorna su valor como 'o*ble.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 26
Por ltimo, la biblioteca cst'io provee varias funciones para entrada/salida generales como print) y
scan) las cuales pueden utilizarse con cadenas de C; as como algunas funciones especficas para
cadenas como (ets y )(ets, de las cuales se recomienda utilizar la ltima ya que permite especificar el
tamao de la secuencia, lo que la hace ms segura. Adems, la biblioteca tambin incluye algunas
funciones para manipular cadenas con formato, que tambin pueden utilizarse al convertir nmeros a
cadenas y viceversa.
c"ar T fgets(c"ar T str int n*m
1I>2 T stream);
Lee desde el stream (s'tin, st'o*t, un archivo, etc) una cadena
hasta que se alcance el nmero mximo de caracteres (n*m-1) o bien un
salto de lnea o el final del archivo.
int s*rintf(c"ar T str const c"ar
T )ormat ...);
Escribe valores en una cadena con formato en forma similar a
print)().
int sscanf(const c"ar T str const
c"ar T )ormat ...);
Interpreta los valores de una cadena con formato en forma similar a
scan)().
Manejo de archivos
Streams de archivos de C++
C++ provee el mecanismo de streams para realizar operaciones de entrada/salida. Los streams son una
abstraccin de los dispositivos en los cuales se puede escribir o extraer datos; su implementacin, en C++,
los define como una fuente o destino de caracteres de longitud indefinida. Adems, pueden estar
asociados a diversos dispositivos fsicos como la consola y archivos en disco.
Por ejemplo, los objetos cin y co*t son instancias de los tipos istream y ostream respectivamente,
es decir son streams de entrada y salida, los cuales estn asociados con la consola (en particular, la
entrada y salida estndar). En el caso de archivos, existen especializaciones de los streams de entrada y
salida para poder vincularlos con archivos y as poder leer y escribir en ellos. La forma de trabajar con
archivos resulta bastante similar al modo en el que se realiza la entrada y salida por consola (con los
objetos cin y co*t) ya que los streams de archivos estn definidos a partir de las mismas clases base.
Para manipular archivos a travs de streams se puede utilizar alguna de las siguientes clases definidas en
el encabezado fstream:
ifstream) para realizar operaciones de lectura desde arc-ios.
ofstream) para realizar operaciones de escritura en arc-ios.
fstream) para realizar operaciones de lectura y escritura en arc-ios.
A continuacin se describirn las operaciones especficas para el manejo de archivos, que ofrecen estos
tipos streams.
Para vincular un stream con un archivo se puede utilizar el mtodo open() (que se encuentra definido
en los tres tipos):
void o*en(const c"ar T )ilename ios!base00openmo'e mo'e);
Tambin es posible asociar el stream con un archivo durante la construccin, por ejemplo:
e3*licit )stream(const c"ar T )ilename ios!base00openmo'e mo'e);
El parmetro )ilename se utiliza para indicar la ruta completa del archivo. Si el archivo se
encuentra en el mismo directorio que el programa, simplemente se indica el nombre del archivo
deseado.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 27
El parmetro mo'e es un parmetro opcional, el cual puede contener una combinacin de los
siguientes valores:
ios00in A"re un arc-io e+istente permitiendo operaciones de entrada #input$.
ios00o*t A"re #o crea en el caso de que no e+ista$ un arc-io permitiendo operaciones se salida #output$.
ios00binar+ Con'igura el stream para que tra"aje en modo "inario #binary$! en ez de te+to.
ios00ate
Con'igura el stream para que antes de cada operacin de salida el indicador de posicin se sit8e al 'inal
del mismo #at end$.
ios00app
Con'igura el stream para que el indicador de posicin se sit8e al 'inal del mismo! de modo que la nuea
in'ormacin se aadir a la ya e+istente #append$.
ios00tr*nc %e elimina el contenido del arc-io lleando su longitud a 0 #truncate$.
Los valores se pueden combinar utilizando el operador de bits OR (|).
Por ejemplo:
o)stream arc6ivo;
arc6ivo.open (.eKemplo.bin. ios00out 9 ios00app 9 ios00binary);
La funcin open() tiene un modo por defecto que se utiliza cuando se abre un archivo sin el segundo
parmetro. El modo por defecto depende de la clase de stream para archivos:
Clase Parmetro de modo por defecto
o)stream ios00o*t
i)stream ios00in
)stream ios00in 9 ios00o*t
Para verificar que el archivo se abri correctamente se utiliza el mtodo is!open():
bool is1o*en();
Para cerrar el archivo y terminar de escribir las salidas pendientes se usa el mtodo close():
void close();
Para verificar si se lleg al final de un archivo durante la lectura se puede utilizar la funcin eo)():
bool eof();
Un problema frecuente es que eo)() no indica que se lleg al final del archivo hasta que efectivamente
se intente leer un dato luego de la ltima lectura correcta. Esto significa que en el caso general, el cdigo
siguiente procesar los datos de una ltima lectura no vlida:
%"ile (Sarc6ivo.eo)()) {
arc6ivo >> 'atos;
$$ Yperaci&n sobre los 'atos
$$ ...
}
Una forma de reestructurar el cdigo para evitar este problema es realizando la lectura de los datos antes
de invocar a eo)():
arc6ivo >> 'atos;
%"ile (Sarc6ivo.eo)()) {
$$ Yperaci&n sobre los 'atos
$$ ...
arc6ivo >> 'atos;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 28
Cabe aclarar que este comportamiento es independiente del tipo de archivo (de texto o binario) y por lo
tanto el mismo se exhibe sin importar que mtodo de lectura o escritura se utilice.
Por ltimo resta mencionar que los streams de archivos cuentan con la posibilidad de ser accedidos en
forma aleatoria para leer o escribir datos en cualquier posicin. Existen indicadores de posicin para la
entrada y salida de datos que pueden ser consultadas a travs de las funciones tellp() y tell(() y
tambin pueden modificarse con los mtodos seeXp() y seeX(().
Archivos de texto
En el caso de los archivos de texto, la salida se realiza a travs del operador <<, del mismo modo que con
el objeto co*t. La lectura de los datos se realiza con el operador >>, de forma equivalente a como se
opera sobre la secuencia de entrada de cin. Tambin son vlidos todos los modificadores y mtodos para
dar formato a la entrada y la salida de los streams asociados a la consola.
A continuacin se presentan las definiciones comunes a una serie de ejemplos que se desarrollarn en lo
que resta de esta seccin:
#include <iostream>
#include <limits>
using names*ace st';
const int >YN\!?CAIN\ " -0;
const int 2ME>2A%Y? " 100;
struct 2mplea'o {
int i';
c"ar nombre8>YN\!?CAIN\:;
c"ar apelli'o8>YN\!?CAIN\:;
float salario;
};
struct 2mplea'os {
2mplea'o emplea'os82ME>2A%Y?:;
int canti'a';
};
void ignorar.inea() {
cin.i(nore(n*meric!limits<st'00streamsiJe>00max() ;4n;);
}
void cargar+m*leados(2mplea'os U emp) {
int i' " 1;
%"ile ((i' S" 0) UU (emp.canti'a' < 2ME>2A%Y?)) {
co*t << .In(resar i' (0 para terminar)04n.;
cin >> i';
i(norar>inea();
if (i' S" 0) {
int pos " emp.canti'a';
emp.emplea'os8pos:.i' " i';
co*t << .In(resar nombre04n.;
cin.(etline(emp.emplea'os8pos:.nombre >YN\!?CAIN\ ;4n;);
co*t << .In(resar apelli'o04n.;
cin.(etline(emp.emplea'os8pos:.apelli'o >YN\!?CAIN\ ;4n;);
co*t << .In(resar salario04n.;
cin >> emp.emplea'os8pos:.salario;
i(norar>inea();
emp.canti'a'PP;
}
}
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 29
void mostrar+m*leados(const 2mplea'os U emp) {
for (int i " 0; i < emp.canti'a'; iPP) {
co*t << emp.emplea'os8i:.i' << . .;
co*t << emp.emplea'os8i:.nombre << . .;
co*t << emp.emplea'os8i:.apelli'o << . .;
co*t << emp.emplea'os8i:.salario << .4n.;
}
}
Ejemplo de escritura:
void guardar+m*leados43t(o)stream U arc6 const 2mplea'os U emp) {
for (int i " 0; i < emp.canti'a'; iPP) {
arc6 << emp.emplea'os8i:.i' << .4n.;
arc6 << emp.emplea'os8i:.nombre << .4n.;
arc6 << emp.emplea'os8i:.apelli'o << .4n.;
arc6 << emp.emplea'os8i:.salario << .4n.;
}
}
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
o)stream arc6?ali'a(.pr*eba.tDt. ios00trunc);
if (arc6?ali'a.is!open()) {
car(ar2mplea'os(emplea'os);
(*ar'ar2mplea'osCDt(arc6?ali'a emplea'os);
arc6?ali'a.close();
} else
co*t << .2rror al crear el arc6ivo 'e sali'a4n.;
return 0;
}
Ejemplo de lectura:
void cargar+m*leados43t(i)stream U arc6 2mplea'os U emp) {
int i " 0;
int i';
arc6 >> i';
%"ile (Sarc6.eo)() UU (i < 2ME>2A%Y?)) {
emp.emplea'os8i:.i' " i';
arc6 >> emp.emplea'os8i:.nombre;
arc6 >> emp.emplea'os8i:.apelli'o;
arc6 >> emp.emplea'os8i:.salario;
iPP;
arc6 >> i';
}
emp.canti'a' " i;
}
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
i)stream arc62ntra'a(.pr*eba.tDt.);
if (arc62ntra'a.is!open()) {
car(ar2mplea'osCDt(arc62ntra'a emplea'os);
mostrar2mplea'os(emplea'os);
arc62ntra'a.close();
} else
co*t << .2rror al abrir el arc6ivo 'e entra'a4n.;
return 0;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 30
Notar que en todos los casos el objeto stream se debe pasar por referencia a las funciones, ya que los
streams no pueden copiarse.
Archivos binarios
Es posible utilizar los streams de archivo para trabajar con archivos binarios. Si bien las secuencias de
entrada y salida se siguen manejando como secuencias de caracteres, se proveen una serie de funciones
que permiten leer y escribir los datos sin que se aplique ningn formato, lo que permite guardar y
recuperar los datos como secuencias de bytes.
Para trabajar con streams de archivos binarios se debe utilizar el indicador ios00binar+ para el
parmetro de modo, al momento de abrir el archivo.
Para escribir datos en los streams se utiliza el mtodo 7rite():
ostream U %rite(const c"ar T s streamsiJe n);
Donde:
s es una referencia a una variable o secuencia de cualquier tipo que debe ser convertida a una
referencia a secuencia de caracteres. Para la conversin puede utilizarse una conversin explcita
de C (c6arT) o bien el operador de conversin reinterpret!cast<const c6arT>()
de C++
10
(que se muestra en en los ejemplos);
n indica el tamao en bytes (o caracteres) de la variable o secuencia a escribir. Para obtener el
tamao en bytes de un tipo o una variable se utiliza el operador siJeo)(),
Para leer datos se utilizar el mtodo rea'():
istream U read(c"ar T s streamsiJe n);
Donde:
s es una referencia a una variable o bloque de datos de cualquier tipo;
n indica el tamao en bytes (o caracteres) de la variable o secuencia a leer.
Ejemplo de escritura:
void guardar+m*leados5in(o)stream U arc6 const 2mplea'os U emp) {
$$ Erimero se (*ar'a la canti'a' 'e emplea'os
arc6.7rite(reinter*ret1cast<const c"ar T>(Uemp.canti'a') si/eof(int));
$$ >*e(o se (*ar'a la parte car(a'a 'el arre(lo 'e emplea'os
arc6.7rite(reinter*ret1cast<const c"ar T>(emp.emplea'os) si/eof(2mplea'o) T
emp.canti'a');
}
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
o)stream arc6?ali'a(.pr*eba.bin. ios00binary9ios00trunc);
if (arc6?ali'a.is!open()) {
car(ar2mplea'os(emplea'os);
(*ar'ar2mplea'os5in(arc6?ali'a emplea'os);
arc6?ali'a.close();
} else
co*t << .2rror al crear el arc6ivo 'e sali'a4n.;
return 0;
}
10
Para ver una explicacin y ejemplos de uso de los distintos mecanismos y operadores de conversin de tipos, ver:
http://cplusplus.com/doc/tutorial/typecasting.html
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 31
Ejemplo de lectura:
void cargar+m*leados5in(i)stream U arc6 2mplea'os U emp) {
$$ Erimero se lee la canti'a' 'e emplea'os
arc6.rea'(reinter*ret1cast<c"ar T>(Uemp.canti'a') si/eof(int));
$$ >*e(o se car(an los emplea'os en el arre(lo
arc6.rea'(reinter*ret1cast<c"ar T>(emp.emplea'os) si/eof(2mplea'o) T
emp.canti'a');
}
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
i)stream arc62ntra'a(.pr*eba.bin. ios00binary);
if (arc62ntra'a.is!open()) {
car(ar2mplea'os5in(arc62ntra'a emplea'os);
mostrar2mplea'os(emplea'os);
arc62ntra'a.close();
} else
co*t << .2rror al abrir el arc6ivo 'e entra'a4n.;
return 0;
}
Como puede observarse en ambos ejemplos, tanto para leer como escribir un arreglo o bloque de
variables, slo hace falta realizar el clculo de <tamao celda><cantidad celdas>, para obtener el
tamao total en bytes de la secuencia.
Strings en archivos binarios
El tipo bsico String de C++, no puede ser almacenado de la misma forma que el resto de los tipos
bsicos. Esto se debe a que los strings son estructuras dinmicas, si se obtiene el espacio utilizado
(mediante siJeo)) de un string vacio y un string con varias lineas de caracteres, se ver que el resultado
es el mismo.
Por lo tanto, para poder almacenar strings en archivos binarios, se debe aplicar el mismo criterio que se
utiliza para almacenar informacin dinmica, es decir, primero se almacena la cantidad de datos a
almacenar y luego los datos en s.
Ejemplo de escritura:
void guardar6tring5in(o)stream U arc6 const strin( U ca'ena) {
int lon(it*' " ca'ena.len(t6();
$$ Erimero se almacena la lon(it*' 'e la ca'ena
arc6.7rite(reinter*ret1cast<const c"ar T> (Ulon(it*') si/eof(int));
$$ >*e(o se almacena la ca'ena (en este caso el res*lta'o 'e
$$ ca'ena.c!str() +a es const c6ar T por lo tanto se evita la
$$ conversi&n me'iante reinterpret!cast<const c6ar T>)
arc6.7rite(ca'ena.c!str() si/eof(c"ar) T lon(it*');
}
Ejemplo de lectura:
void cargar6tring5in(i)stream U arc6 strin( U ca'ena) {
int lon(it*';
$$ Erimero se lee la lon(it*' 'e la ca'ena
arc6.rea'(reinter*ret1cast<c"ar T> (Ulon(it*') si/eof(int));
$$ ?e 'e)ine *na ca'ena 'e @ para leer los caracteres. ?e 'e)ine 'e
$$ lon(it*' P 1 para completar la ca'ena con ;40;
c"ar arr@a'ena8lon(it*' P 1:;
$$ ?e lee la ca'ena
arc6.rea'(arr@a'ena si/eof(c"ar) T lon(it*');
$$ ?e completa el arre(lo con ;40; para )ormar *na ca'ena 'e caracteres
$$ estilo @
arr@a'ena8lon(it*': " ;40;;
$$ A6ora se p*e'e asi(nar la ca'ena 'e caracters al strin(
ca'ena " arr@a'ena;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 32
Streams de archivos de C
C++ provee la implementacin de streams original de C, la cual puede utilizarse a travs de la biblioteca
cstdio. Existe un nico tipo de stream en C definido por el tipo 1I>2, el cual contiene la secuencia de
entrada y salida e informacin, como la posicin a la que se est accediendo, el estado, etc.
Para abrir archivos utilizamos la funcin )open:
1I>2 T fo*en(const c"ar T )ilename const c"ar T mo'e);
El parmetro )ilename se utiliza para indicar la ruta -asta el arc-io! incluyendo el nom"re de dic-o
arc-io. %i el arc-io se encuentra en el mismo directorio donde se genera el ejecuta"le de nuestro
programa! simplemente se indica el nom"re del arc-io deseado.
La cadena de modo (parmetro mo'e) puede contener una combinacin de los siguientes indicadores:
r : abre un archivo existente para lectura;
% : crea el archivo o vaca un archivo existente, dejndolo listo para escritura;
a : crea el archivo o mantiene el contenido de uno existente aadiendo los nuevos datos al final.
Seguido de alguno de los modificadores:
7 : agrega escritura al modo r o lectura a los modos 7 y r.
b : hace que los archivos sean binarios (por defecto son de texto).
Si se pudo abrir el archivo correctamente, la funcin )open() deuele una re'erencia al stream
#1I>2T$! o "ien un puntero nulo #0 o N=>>$ en el caso contrario.
Para cerrar un archivo se utiliza la funcin )close():
int fclose(1I>2 T stream);
Para verificar si se lleg al final de un stream, durante la lectura, se utiliza la funcin )eo)():
int feof(1I>2 T stream);
Al igual que con los streams de C++ y el mtodo eo)(), esta funcin no retornar el valor de fin de
archivo (0 o 2Y1) hasta que se realice una operacin de lectura que lo encuentre. Es por eso que, en
general, el cdigo que sigue realizar una operacin sobre datos no vlidos en la ltima iteracin:
%"ile ()eo)(arc6ivo) S" 2Y1) {
)scan)(arc6 .V.... U'atos);
$$ Yperaci&n sobre los 'atos
$$ ...
}
Como se coment anteriormente se puede resolver el problema realizando la lectura de datos antes de
llamar a )eo)() y luego procesar los datos. A su vez existe otra solucin que consiste en utilizar el valor
devuelto por las funciones de lectura de streams de C ()scan), )rea', etc), el cual indica el nmero de
elementos ledos, para controlar el corte del ciclo (por lo que ya no resulta necesario utilizar )eo)()):
%"ile ()scan)(arc6 .V.... U'atos) S" 0) {
$$ Yperaci&n sobre los 'atos
$$ ...
}
Archivos de texto
Cuando se trabaja con archivos de texto se utilizan funciones similares a las ya vistas para el manejo de
entrada y salida por consola (prin)(), scan)(), )(ets(), etc), varias de las cuales utilizan el
mecanismo de la cadena de formato para realizar la interpretacin y formateo de los valores de los
distintos tipos de informacin que se lee y escribe. A diferencia de las funciones que se encuentran
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 33
asociadas con los streams de la entrada y salida estndar de la consola (st'in y st'o*t), estas
funciones introducen un parmetro adicional para indicar el stream sobre el cual se desea operar.
Para escribir datos en un stream (de archivo) se utiliza la funcin )print() que opera igual que
prin)():
int f*rintf(1I>2 T stream const c"ar T )ormat ...);
Para leer datos se utiliza la funcin )scan)() que es similar a scan)():
int fscanf(1I>2 T stream const c"ar T )ormat ...);
Al igual que con los streams de C++ existe la posibilidad de realizar accesos de forma aleatoria a
cualquier posicin del stream de archivo tanto para escribir como para leer datos. Esto se consigue
manipulando el indicador de posicin del stream. Las funciones )(etpos() y )tell() devuelven la
posicin actual del indicador. Las funciones )setpos() y )seeX() modifican el indicador llevndolo
a la posicin deseada.
Ejemplo de lectura:
void guardar+m*leados43t(1I>2 T arc6 const 2mplea'os U emp) {
for (int i " 0; i < emp.canti'a'; iPP) {
)print)(arc6 .V'4n. emp.emplea'os8i:.i');
)print)(arc6 .Vs4n. emp.emplea'os8i:.nombre);
)print)(arc6 .Vs4n. emp.emplea'os8i:.apelli'o);
)print)(arc6 .V)4n. emp.emplea'os8i:.salario);
}
}
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
1I>2 T arc6?ali'a " )open(.pr*eba.tDt. .7.);
if (arc6?ali'a S" 0) {
car(ar2mplea'os(emplea'os);
(*ar'ar2mplea'osCDt(arc6?ali'a emplea'os);
)close(arc6?ali'a);
} else
co*t << .2rror al crear el arc6ivo 'e sali'a4n.;

return 0;
}
Ejemplo de escritura:
void cargar+m*leados43t(1I>2 T arc6 2mplea'os U emp) {
$$ ?e (enera 'in3micamente el )ormato para leer las ca'enas limitan'o
$$ la canti'a' 'e caracteres
c"ar strin(1ormat8-0:;
sprint)(strin(1ormat .VVV's4n. >YN\!?CAIN\);
int i " 0;
int i';
)scan)(arc6 .V'4n. Ui');
%"ile (()eo)(arc6) S" 2Y1) UU (i < 2ME>2A%Y?)) {
emp.emplea'os8i:.i' " i';
)scan)(arc6 strin(1ormat Uemp.emplea'os8i:.nombre);
)scan)(arc6 strin(1ormat Uemp.emplea'os8i:.apelli'o);
)scan)(arc6 .V)4n. Uemp.emplea'os8i:.salario);
iPP;
)scan)(arc6 .V'4n. Ui');
}
emp.canti'a' " i;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 34
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
1I>2 T arc62ntra'a " )open(.pr*eba.tDt. .r.);
if (arc62ntra'a S" 0) {
car(ar2mplea'osCDt(arc62ntra'a emplea'os);
mostrar2mplea'os(emplea'os);
)close(arc62ntra'a);
} else
co*t << .2rror al abrir el arc6ivo 'e entra'a4n.;
return 0;
}
Archivos binarios
Para manipular archivos binarios hay que incluir el modificador b a la cadena de modo de la funcin
)open().
Para leer del archivo se utiliza la funcin )rea'():
siJe!t fread(void T ptr siJe!t siJe siJe!t co*nt 1I>2 T stream);
donde ptr es un puntero a la variable o bloque donde se van a almacenar los datos ledos del archivo,
siJe es el tamao en bytes de cada elemento a leer, co*nt es la cantidad de elementos que se van a leer
y stream es el archivo de donde van a ser ledos.
Esta funcin devuelve el nmero de elementos ledos; dicho valor puede ser comparado con el parmetro
co*nt* s los alores son distintos! se puede asegurar que ocurri un error en la lectura.
Para escribir en el archivo se utiliza la funcin )7rite():
siJe!t f%rite(const void T ptr siJe!t siJe siJe!t co*nt 1I>2 T stream);
donde ptr es un puntero a la variable donde se encuentran los elementos a guardar en el archivo. En este
caso se agrega el modificador const para indicar que el contenido de dic-a aria"le no a a ser
modi'icado por la 'uncin )7rite. El parmetro siJe es el tamao en bytes de cada elemento a
escribir, co*nt es la cantidad de elementos que se van a escribir y stream es el archivo donde van a ser
escritos.
Esta funcin devuelve el nmero de elementos escritos en el archivo; dicho valor puede ser comparado
con el parmetro co*nt! s los alores son distintos se puede asegurar que ocurri un error en la
escritura.
Ejemplo de escritura:
void (*ar'ar2mplea'os5in(1I>2 T arc6 const 2mplea'os U emp) {
$$ Erimero se (*ar'a la canti'a' 'e emplea'os
)7rite(Uemp.canti'a' si/eof(int) 1 arc6);
$$ >*e(o se (*ar'a la parte car(a'a 'el arre(lo 'e emplea'os
)7rite(emp.emplea'os si/eof(2mplea'o) emp.canti'a' arc6);
}
int main() {
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
1I>2 T arc6?ali'a " )open(.pr*eba.bin. .7b.);
if (arc6?ali'a S" 0) {
car(ar2mplea'os(emplea'os);
(*ar'ar2mplea'os5in(arc6?ali'a emplea'os);
)close(arc6?ali'a);
} else
co*t << .2rror al crear el arc6ivo 'e sali'a4n.;
return 0;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 35
Ejemplo de lectura:
void car(ar2mplea'os5in(1I>2 T arc6 2mplea'os U emp) {
$$ Erimero se lee la canti'a' 'e emplea'os
)rea'(Uemp.canti'a' si/eof(int) 1 arc6);
$$ >*e(o se car(an los emplea'os en el arre(lo
)rea'(emp.emplea'os si/eof(2mplea'o) emp.canti'a' arc6);
}
int main()
{
2mplea'os emplea'os;
emplea'os.canti'a' " 0;
1I>2 T arc62ntra'a " )open(.pr*eba.bin. .rb.);
if (arc62ntra'a S" 0) {
car(ar2mplea'os5in(arc62ntra'a emplea'os);
mostrar2mplea'os(emplea'os);
)close(arc62ntra'a);
} else
co*t << .2rror al abrir el arc6ivo 'e entra'a4n.;

return 0;
}
Punteros y manejo de memoria
C++ maneja varias regiones de memoria durante la ejecucin de un programa. La discusin de esta
seccin se centra en dos de ellas, en las cuales el programador puede manipular sus variables: la pila y el
montculo.
3a pila se utiliza para almacenar informacin de las sub-rutinas activas durante la ejecucin (funciones,
variables de tamao fijo, puntos de retorno, etc). Las variables de la pila cuentan con un nombre y un tipo
y pueden declararse en cualquier lugar de un bloque de cdigo. Es el sistema de ejecucin el que se
encarga de reservar el espacio para estas variables, as como inicializarlas y destruirlas (liberando el
espacio reservado) cuando se termina la ejecucin del bloque en el que fueron definidas.
El montculo se utiliza para almacenar informacin de tamao variable durante la ejecucin. Las
variables del heap tienen tipo pero no cuentan con un nombre. Por lo tanto, se manipulan a travs de otras
variables denominadas punteros. Las variables que se encuentran en el montculo son administradas
explcitamente por el programador, por lo que es este quin debe reservar el espacio necesario para las
mismas, inicializarlas y destruirlas a travs de los punteros y sus operaciones especiales.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 36
Los punteros (tam"i&n denominados 1apuntadores2 o 1re'erencias2) son un tipo de variable que contiene
la direccin de memoria de otras variables en el montculo o en la pila. Los punteros en general se definen
de forma que puedan referenciar un tipo determinado de variables. >o e+iste un t&rmino pre'erido para
denominar a 1lo que apunta2 un puntero! aunque suele utilizarse 1re'erente2.
Declaracin de los punteros:
<tipo!obKeto> 8 <eti,*eta!p*ntero>;
Como se dijo anteriormente los valores de los punteros son direcciones de memoria. La asignacin es la
operacin con punteros vlida ms bsica, la cual permite copiar en el puntero la direccin contenida en
otro puntero o la obtenida a travs de alguno de los operadores de referencia y reserva de memoria que se
vern continuacin.
Para iniciar un puntero que no hace referencia a un espacio de memoria vlido es necesario asignar el
valor constante 0 o bien el valor de la macro N=>> (definida en la biblioteca cst'lib).
Operadores relacionados con punteros
8<p*ntero>
Es el operador de indireccin. El mismo permite acceder al valor del
objeto referenciado (para leerlo o modificarlo). El operador de
indireccin tambin suele llamarse operador de desreferencia, y se
llama desreferenciar a la accin de acceder, a travs del mismo, al
contenido de un espacio en memoria.
<p*ntero>(-<miembro>
Es el operador de acceso a miembros. El mismo realiza una
indireccin que permite acceder a los campos de una estructura o los
miembros de una clase. Es equivalente a escribir
(*<p*ntero>)!<miembro>.
,<variable>
Es el operador de referencia el cual devuelve la direccin en
memoria de un objeto.
Por ejemplo:
int n; $$ %eclaramos *na variable entera
int T ptr; $$ %eclaramos *n p*ntero a variables 'e tipo entero
ptr " Un; $$ Asi(namos al p*ntero la 'irecci&n 'e memoria 'e la variable n (notar
,*e esta 'irecci&n se enc*entra en la pila)
Tptr " 10; $$ Mo'i)icamos el conteni'o 'e la variable re)erencia'a por el p*ntero
C++ tambin cuenta con los operadores ne7 y 'elete que permiten crear y destruir variables a travs
de punteros. Estos operadores se explicarn a continuacin junto con las funciones de C que cumplen el
mismo propsito.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 37
Operaciones para obtener y liberar memoria
Operaciones para obtener memoria
Existen dos operaciones para obtener memoria: ne7 (introducido en C++) y malloc (disponible a travs
de cst'lib):
<tipo!obKeto> 8 <eti,*eta!p*ntero> = ne% <tipo!obKeto>;
<tipo!obKeto> 8 <eti,*eta!p*ntero> = (<tipo!obKeto>8) malloc(<tamaLo!blo,*e>);
,or ejemplo)
int T ptr " ne% int; $$ Aeservamos espacio en el 6eap para *n variable entera e
inicialiJamos *n p*ntero con *na re)erencia al mismo
Tptr " 10; $$ Mo'i)icamos el conteni'o 'e la variable re)erencia'a
por el p*ntero
Aqu se ve un contraste respecto a las regiones de memoria donde se encuentran la variable local y la
variable que administra el programador, la cual es creada mediante la instruccin ne7. La memoria
administrada por el programador no es liberada hasta que no se realice en forma explcita, a travs de la
instruccin 'elete.
Operaciones para liberar memoria
Existen dos operaciones para liberar memoria: 'elete (introducido en C++) y )ree (disponible a
travs de cst'lib):
delete <eti,*eta!p*ntero>;
free(<eti,*eta!p*ntero>);
Por ejemplo:
delete ptr;
ptr " 0;
Aclaraciones para la operacin 'elete)
3o que se li"era es el espacio en memoria al que re'erencia el alor del puntero #no el puntero en
s mismo$. El alor del puntero al utilizar 'elete de"e ser alguno retornado por el operador
ne7! es decir! el o"jeto eliminado de"e encontrarse en el montculo #por otra parte! cualquier
intento de utilizar 'elete so"re una re'erencia a una aria"le de la pila arrojar un error$.
3uego de ejecutar 'elete! la posicin de memoria del o"jeto que re'erencia"a el puntero queda
inalidada #o como suele decirse el puntero queda inalidado o colgado$. A continuacin! es
posi"le reinicializarlo con una nuea direccin de memoria lida o "ien asignarle 0 o N=>> a 'in
de eitar errores! ya que si intenta desre'enciar un puntero inlido o oler a ejecutar la
operacin 'elete so"re el mismo llear a errores de ejecucin.
>o es necesario eri'icar si el puntero es nulo antes de llamar a 'elete.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 38
Consideraciones sobre la utilizacin de malloc y free
Es posible y est bien utilizar ne7 y 'elete, y malloc (as como las variantes calloc y realloc)
y )ree en un mismo programa. Sin embargo, hay que tener cuidado de no utilizar )ree sobre un
espacio de memoria obtenido a travs de ne7. De igual forma, no se debe utilizar 'elete sobre
memoria obtenida a travs de malloc. El problema es que las funciones no fueron especificadas por el
lenguaje para trabajar en forma conjunta, y no es posible garantizar que vayan a funcionar bien en todas
las plataformas.
Sin embargo, para la mayora de los casos de uso ms frecuentes se recomienda utilizar ne7 y 'elete
por las razones que se enumeran a continuacin:
ne7 es una operacin de tipado seguro. Es decir, devuelve punteros de un tipo determinado;
malloc en cambio, devuelve un puntero de tipo sin valor (void*). Por ejemplo:
int T ptr!ne7 " ne% int;
int T ptr!malloc " (intT) malloc(si/eof(int));
ne7 y 'elete no solo reservan y liberan el espacio en memoria de los objetos si no que adems
se encargan de invocar a las funciones constructoras y destructoras respectivamente. Por otra
parte, malloc y )ree no ofrecen soporte para clases, es decir que durante la creacin y
liberacin de los objetos que sean instancias de clases no sern correctamente inicializados ni
destruidos.
Obteniendo bloques de memoria contigua
Es posible reservar espacio para ms de una variable de modo que las mismas queden ubicadas en
posiciones de memoria consecutivas:
<tipo!obKeto> 8 <eti,*eta!p*ntero> " ne% <tipo!obKeto> #<canti'a'!variables>$;
Por ejemplo:
int T ptr!blocX " ne% int810:;
Para liberar bloques de memoria se debe utilizar la siguiente variante de la operacin 'elete:
delete #$ <eti,*eta!p*ntero>;
Por ejemplo:
delete 8: ptr!blocX;
No es necesario indicar de ninguna forma ni el tipo ni la cantidad de elementos de los arreglos que se
liberan con 'elete8: (o )ree). El sistema de tiempo de ejecucin se encarga de registrar esa
informacin automticamente.
No hay que confundir un bloque de memoria contigua con un arreglo. Si bien existen similitudes en la
forma de manipularlos (gracias a caractersticas propias de los arreglos y a la aritmtica de punteros) y
pueden considerarse equivalentes en algunos aspectos, no son lo mismo. En las secciones siguientes se
profundizar sobre estas equivalencias y diferencias.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 39
Arreglos y punteros
Siempre que un arreglo aparece como parte del lado izquierdo o derecho de una expresin el compilador
genera implcitamente una conversin a un puntero constante al primer elemento del arreglo. Esto implica
que para toda manipulacin de los elementos de los arreglos a travs de la notacin de subndices en
realidad se est utilizando la expresin de subndices de la aritmtica de punteros.
La expresin de subndice tiene la forma +9#+:$, donde +9 es un puntero a un elemento de tipo T y +:
es una expresin de tipo entero. El resultado es un valor de tipo T, equivalente al obtenido a travs de la
expresin T(+97+:) (esto es el valor de la variable que se encuentra desplazndose E2 celdas a partir de
la posicin indicada por E1).
Teniendo en cuenta lo dicho anteriormente veremos que los fragmentos de cdigo que siguen son
funcionalmente equivalentes, pero introduciendo pequeas variantes en cuanto a la forma de acceso a los
elementos del arreglo.
1
2
3
#
-
O
// versin 1
int arr8-: " {123#-};
for (int i"0; i<-; iPP)
arr8i: " arr8i:T2;
for (int i"0; i<-; iPP)
co*t << arr8i:;
// versin 2
int arr8-: " {123#-};
int T ptr " arr;
for (int i"0; i<-; iPP)
arr8i: " ptr8i:T2;
for (int i"0; i<-; iPP)
co*t << ptr8i:;
// versin 3
int arr8-: " {123#-};
int T ptr " arr;
for (int i"0; i<-; iPP)
ptr8i: " arr8i:T2;
for (int i"0; i<-; iPP)
co*t << arr8i:;
La primera versin declara e inicializa un arreglo, y utiliza la notacin de subndice ya vista para
modificar los valores del mismo y luego imprimirlos. Recordando que tanto en las expresiones de la lnea
3 como la lnea 5, el arreglo es convertido implcitamente a un puntero, es que se introduce el puntero
ptr en las versiones 2 y 3 del cdigo anterior. Como se ve, ptr se inicializa con el valor de arr (que en
esa asignacin, por supuesto, tambin se convierte en un puntero), lo que lleva a que ptr referencie la
primera posicin de dicho arreglo. Luego en la versin 2 ptr es utilizado para leer los valores del arreglo
en vez de arr, y en la versin 3 ptr se utiliza para el acceso de escritura en su lugar.
Los elementos de un arreglo pueden ser accedidos a travs de un puntero utilizando una sintaxis similar.
Sin embargo, el arreglo y el puntero son objetos distintos. Al mismo tiempo, un bloque en memoria
dinmica puede utilizarse para simular un arreglo y es posible manipularlo en forma equivalente pero
tampoco es un arreglo tradicional (ya que entre otras cosas debe ser eliminado manualmente a diferencia
de los arreglos que son inicializados y destrudos en forma automtica). Para ejemplificar, se muestra la
declaracin e inicializacin de un puntero a un elemento del arreglo, un puntero al arreglo
11
, y un puntero
a un bloque de caractersticas similares al arreglo original:
int arr810:;
int T ptr " arr; $$ E*ntero al primer elemento
int (T ptr!arr)810: " Uarr; $$ E*ntero al arre(lo
int T ptr!blocX " ne% int810:; $$ E*ntero a *n blo,*e
11
Hay que tener en cuenta que los punteros a arreglo slo pueden hacer referencia a arreglos de la dimensin especificada.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 40
Completamos el ejemplo anterior con el cdigo correspondiente a la inicializacin e impresin del
contenido de las estructuras:
for (int i"0; i<10; iPP)
ptr8i: " iP1;
for (int i"0; i<10; iPP)
co*t << ptr8i:;
for (int i"0; i<10; iPP)
(Tptr!arr)8i: " iP1;
for (int i"0; i<10; iPP)
co*t << (Tptr!arr)8i:;
for (int i"0; i<10; iPP)
ptr!blocX8i: " iP1;
for (int i"0; i<10; iPP)
co*t << ptr!blcoX8i:;
Arreglos como parmetros de funciones
En primer lugar, debido a que no es posible la asignacin entre arreglos, no es posible el pasaje por copia
de los mismos. Es ms, como los nombres de los arreglos se convierten en punteros, cuando pasamos un
arreglo a una funcin, en realidad se pasa un puntero al primer elemento. Por ejemplo, si se quisiera crear
una funcin que manipule arreglos de una dimensin de tamao variable se podra escribir utilizando la
notacin de arreglos:
void funcion(int arr8: int lon(it*') {
...
}
o bien utilizando la notacin de punteros que es equivalente:
void funcion(int T arr int lon(it*') {
...
}
En las funciones anteriores, aunque el puntero al primer elemento del arreglo se pasa por copia, es posible
modificar el contenido del arreglo porque, como no es vlida la asignacin de arreglos, no se puede
realizar una copia del arreglo, si no que la referencia sigue siendo a la secuencia de celdas original. Sin
embargo, es posible cambiar la definicin de los parmetros anteriores para que las referencias a los
elementos del bloque de memoria sean constantes de modo que los elementos de los arreglos no puedan
modificarse desde las funciones (es decir, un mecanismo de restriccin al acceso de los arreglos para
ciertas porciones del cdigo de modo que slo se pueda leerlos).
Una consideracin muy importante es que la conversin del nombre del arreglo a un puntero sucede una
sola vez (no es recursiva). Por lo tanto, en el pasaje como parmetro de arreglos de dimensin mayor a
uno, la situacin es un poco ms compleja y la solucin involucra el pasaje de un puntero a un arreglo, lo
que implica que las funciones podrn definirse para trabajar sobre arreglos de una dimensin especfica.
La siguiente referencia contiene una discusin muy buena acerca de este tema:
http://c-faq.com/aryptr/pass2dary.html
A raz de esto ltimo, puede apreciarse que trabajar con arreglos de mltiples dimensiones y tamaos
variables puede ser problemtico.
Arreglos dinmicos
Una solucin al problema expuesto en la seccin anterior es trabajar con arreglos dinmicos como se
explica en:
http://c-faq.com/aryptr/dynmuldimary.html
Estos arreglo dinmicos son los arreglos simulados a travs de bloques de memoria contigua que ya se
mencion. Existen varias ventajas al trabajar con arreglos implementados de esta forma:
La principal es que el tamao de estos arreglos lo podemos determinar en tiempo de ejecucin, a
diferencia de los arreglos estticos los cuales requieren que su tamao se especifique en tiempo de
compilacin.
La definicin y manipulacin, especialmente el pasaje como parmetro es uniforme y por lo tanto
resulta mucho ms intuitivo.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 41
La naturaleza dinmica de estas estructuras lleva a que el cdigo para manipular arreglos de
mltiples dimensiones sea inherentemente genrico y en consecuencia reutilizable, en
contraposicin con las matrices tradicionales que obligan a definir funciones que trabajen con
dimensiones especficas.
Lo que sigue es un ejemplo muy simple de como trabajar con un arreglo dinmico de dos dimensiones:
$T 2s m*+ importante el pasaKe por re)erencia 'el p*ntero a la matriJ por,*e 'e
otra )orma la matriJ ser3 crea'a pero el p*ntero ori(inal no ser3 mo'i)ica'o 'e
mo'o ,*e nos permita acce'er a la misma m3s a'elante T$
void crear;atri/:<(int TT U matriJ int anc6o int alto) {
matriJ " ne% intT8alto:;
for (int ) " 0; ) < alto; )PP)
matriJ8): " ne% int8anc6o:;
}
void eliminar;atri/:<(int TT U matriJ int anc6o int alto) {
for (int ) " 0; ) < alto; )PP)
delete 8: matriJ8):;
delete 8: matriJ;
matriJ " 0;
}
void cargar;atri/:<(int TT matriJ int anc6o int alto) {
for (int ) " 0; ) < alto; )PP)
for (int c " 0; c < anc6o; cPP)
matriJ8):8c: " ) T anc6o P c P 1;
}
void mostrar;atri/:<(int TT matriJ int anc6o int alto) {
for (int ) " 0; ) < alto; )PP) {
for (int c " 0; c < anc6o; cPP)
co*t << matriJ8):8c: << . .;
co*t << .4n.;
}
}
int main(int ar(c c"ar T ar(v8:)
{
int TT matriJ " 0;
int anc6o " 10;
int alto " -;
crearMatriJ2%(matriJ anc6o alto);
car(arMatriJ2%(matriJ anc6o alto);
mostrarMatriJ2%(matriJ anc6o alto);
eliminarMatriJ2%(matriJ anc6o alto);
return 0;
}
Arreglos de tamao variable y el estndar C99
En el estndar de C de 1999 se agrega una extensin a la definicin del tamao de los arreglos. Esta
nueva definicin permite utilizar una expresin no constante para determinar el tamao de un arreglo.
Si bien esto permite la declaracin de un arreglo cuyo tamao se determina en tiempo de ejecucin, no se
est definiendo un arreglo dinmico, ya que la expresin no constante se evaluar nicamente al momento
de crear el arreglo. El tamao del arreglo no podr modificarse una vez definido. A este tipo de arreglos se
los conoce como arreglos de tamao variable.
Por ejemplo, podramos definir un arreglo, cuyo tamao es determinado en tiempo de ejecucin, de la
siguiente forma:
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 42
int n;
cin >> n;
int arre(lo8n:;
$$ Yperaciones sobre el arre(lo.
Si bien las ltimas versiones del compilador GCC han adoptado casi por completo el estndar C99,
incluyendo los arreglos de tamao variable, todava no han sido adoptados por la mayora de los
compiladores. Por lo tanto, utilizar este tipo de arreglo, comprometera la portabilidad de nuestro cdigo.
Por otro lado, el arreglo es almacenado en la pila, con lo cual se puede generar un error si el arreglo es de
un tamao demasiado grande.
Por estas razones, recomendamos la definicin de arreglos dinmicos mediante la utilizacin de bloques
de memoria contigua, como se vi anteriormente.
Aritmtica de punteros
Es posible obtener un desplazamiento hacia otras posiciones de memoria partiendo de la posicin
indicada por un puntero.
Una forma es utilizando las operaciones de sumas y restas:
<p*ntero> P <'esplaJamiento>
<p*ntero> Q <'esplaJamiento>
Otra forma es utilizando la notacin de subndice:
<p*ntero>8<'eJplaJamiento>:
Esta operacin implica un desplazamiento y una desreferencia.
Cuando hablamos de aritmtica de punteros, hablamos de las operaciones bsicas o elementales que
podemos realizar con los punteros.
Hay que notar que las operaciones con subndices son las que nos permiten trabajar fcil e intuitivamente
con punteros y arreglos, dando lugar a la denominada equivalencia que se mencion anteriormente.
Las operaciones de suma o resta slo son vlidas con punteros con tipo; no estn definidas sobre punteros
sin tipo: voi' T. Esto se debe a que no es posible determinar el tamao de los objetos referenciados por
un puntero sin tipo.
Tambin es necesario que el operando izquierdo sea del tipo puntero y el operando derecho sea de tipo
entero.
Como es evidente, la unidad del desplazamiento no es un byte, sino una cantidad de bytes igual al tamao
del tipo del objeto (siJeo)(<tipo!obKeto>)) almacenado en cada celda de un arreglo o un bloque.
A travs de las operaciones de desplazamiento se puede alcanzar virtualmente cualquier posicin de
memoria. Sin embargo, slo los desplazamientos sobre posiciones de arreglos estticos o dinmicos
tienen sentido. Hay que tener especial cuidado de no sobrepasar los lmites de los arreglos ya que el
lenguaje no verifica esto de ninguna forma.
Por ltimo hay que mencionar que tambin est definida la resta entre punteros:
<p*ntero1> Q <p*ntero2>
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 43
Dicha operacin es posible entre punteros del mismo tipo. Adems slo tiene sentido si ambos punteros
hacen referencia a posiciones de un mismo arreglo esttico o celdas de un mismo bloque de memoria
contigua.
Veamos un pequeo ejemplo:
void cargar=rreglo (int T arre(lo int limite) {
for(int i " 0; i < limite; iPP)
arre(lo8i: " i; $$ T(arre(lo P i) " i;
}
void mostrar=rreglo (int T arre(lo int limite) {
for(int i " 0; i < limite; iPP)
*rintf(.Vi4n. arre(lo8i:); $$ print)(.Vi4n.T(arre(lo P i));
}
int main()
{
int T arr " ne% int810:; $$ int arr810:;
car(arArre(lo(arr 10); $$ car(arArre(lo(Uarr80: 10);
mostrarArre(lo(arr P - -); $$ mostrarArre(lo(Uarr8-: -);
delete 8: arr;
return 0;
}
En este ejemplo vemos algunas de las operaciones que podemos realizar con punteros. La idea es que
cualquier lnea puede ser reemplazada por el cdigo comentado que le sigue y el programa resultante
seguira comportndose de la misma forma.
Es claro que el cambio ms significativo es cambiar el arreglo esttico por el dinmico. Pero an as el
programa seguir funcionando de la misma forma.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 44
Clases
El mecanismo de clases es una de las extensiones principales que incorpora el lenguaje C++, a la
programacin procedural propia de C. Esto posibilita la orientacin a objetos que constituye un
paradigma nuevo de programacin.
Una clase se puede definir como una estructura que agrupa datos y funciones, permitiendo su
encapsulamiento. Las clases representan nuevos tipos de datos.
Las clases estn formadas por dos tipos de componentes o miembros: las propiedades o atributos (los
datos) y los mtodos o funciones. Formalmente se definen como variables y mtodos de instancia.
Un objeto es una instancia de una clase determinada. Los objetos son los encargados de procesar los
mensajes recibidos, es decir, de responder ante el llamado a cada una de las funciones. Mediante los
mtodos se podrn manipular los datos propios de los objetos.
Definicin de clases - Declaracin de la interfaz
Para definir una clase se utiliza la siguiente sintaxis:
class <nombre!clase>
{
{<nivel!'e!acceso>&}
<lista!'e!miembros>
{<nivel!'e!acceso>&}
<lista!'e!miembros>
]
};
El nombre de la clase debe ser un identificador vlido. Este identificador definir un nuevo tipo de datos
que luego se utilizar para declarar variables (o instanciar objetos) del tipo de la clase.
Dentro del cuerpo de la clase, se deben definir las variables y funciones miembro que la compondrn.
Adems, opcionalmente, se puede definir un nivel de acceso para cada una de ellas.
El nivel de acceso, modifica los permisos de acceso a los miembros definidos antes de la declaracin de
un nuevo nivel de acceso. Existen tres alternativas:
*ublic: los miembros pblicos son accesibles desde cualquier parte donde el objeto es visible.
*rivate: los miembros privados slo son accesibles desde los propios miembros de la clase.
*rotected: los miembros protegidos slo son accesibles desde los propios miembros de la
clase, funciones o clases friends y miembros de clases derivadas.
Si no se especifica ningn nivel de acceso, por defecto, los miembros de una clase son privados. Por lo
tanto, cualquier miembro declarado antes de la definicin de un nivel de acceso es considerado como
privado.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 45
Por ejemplo:
class E*nto
{
int D;
int +;
*ublic0
void cargar>oordenadas(int cD int c+);
int coordenada?() const;
int coordenada@() const;
};
O lo que es equivalente:
class E*nto
{
*ublic0
void cargar>oordenadas(int cD int c+);
int coordenada?() const;
int coordenada@() const;
*rivate:
int D;
int +;
};
En este ejemplo, se define una clase E*nto, la cual contiene dos atributos privados, de tipo entero, D e +;
y tres mtodos de instancia pblicos: cargar>oordenadas, coordenada? y coordenada@.
Se denomina interfaz a la parte pblica de una clase. La interfaz generalmente slo consta de funciones;
rara vez se hacen pblicos los atributos. Al quedar ocultos los datos se hace efectiva la abstraccin y el
encapsulamiento de los tipos de datos abstractos. De esta forma, la interfaz de funciones asla a los
usuarios de los cambios en los tipos y cantidad de atributos.
En general, los cambios en las estructuras de datos de las clases no deberan afectar al resto del cdigo
que las utiliza, esto es, suponiendo que la definicin de los mtodos no vara.
Instanciacin y uso
En el fragmento de cdigo siguiente veremos como se declara un objeto de tipo E*nto y como se
invocan sus mtodos:
E*nto p*nto;
p*nto.car(ar@oor'ena'as(3#);
co*t << .@oor'ena'a G0 . << p*nto.coor'ena'aG()
<< . Q @oor'ena'a ^0 . << p*nto.coor'ena'a^();
Un objeto es como una variable de registro, donde toda la manipulacin de los datos se hace a travs de
los mtodos. Por otra parte, si se quisiera acceder directamente los atributos de las coordenadas D e +
(para consultar o modificar su valor) se producira un error de compilacin:
$$ @a'a lMnea pro'*ce *n error 'e compilaci&n0 D e + son priva'as.
p*nto.D " 3;
p*nto.+ " #;
co*t << .@oor'ena'a G0 . << p*nto.D << . Q @oor'ena'a ^0 . << p*nto.+;
Como se mencion anteriormente, el nombre de la clase corresponde a un nuevo tipo de datos. Por lo
tanto, tambin es posible definir y manipular punteros del tipo de la clase, como se ve en el ejemplo
siguiente:
E*nto T p*nto " ne% E*nto();
p*ntoQ>car(ar@oor'ena'as(3#);
co*t << .@oor'ena'a G0 . << p*ntoQ>coor'ena'aG()
<< . Q @oor'ena'a ^0 . << p*ntoQ>coor'ena'a^();
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 46
delete p*nto;
Es importante notar que la invocacin de los mtodos de los objetos referenciados es similar a la forma de
acceder a los campos de un registro a travs de un puntero. El operador -> funciona como una
desreferencia y acceso a miembro, que puede utilizarse tanto para atributos como funciones.
Definicin/Implementacin de la interfaz
Como se puede ver en el ejemplo de la definicin de la clase E*nto, solamente se incluye la declaracin
de los mtodos de instancia, pero no su definicin. Para que una clase est completa es necesario
implementar todos los mtodos.
Para esto existen dos alternativas. La primer opcin es implementar los mtodos a continuacin de la
declaracin. Esto es til cuando el cdigo de cada mtodo es pequeo, de lo contrario suele dificultar su
legibilidad.
Por ejemplo:
class E*nto
{
*ublic0
void cargar>oordenadas(int cD int c+) {
D " cD;
+ " c+;
}
int coordenada?() const {
return D;
}
int coordenada@() const {
return +;
}
*rivate:
int D;
int +;
};
La segunda alternativa consiste en implementar los mtodos fuera de la clase en cuestin. Para esto se
utiliza el operador de mbito (::), el cual nos permite especificar la clase a la cual pertenece el mtodo que
se est definiendo:
<tipo!retorno> <nombre!clase>&&<nombre!)*nci&n>(<lista!'e!par3metros>);
Por ejemplo:
class E*nto
{
*ublic0
void cargar>oordenadas(int cD int c+);
int coordenada?() const;
int coordenada@() const;
*rivate:
int D;
int +;
};
void )unto&&cargar>oordenadas(int cD int c+)
{
D " cD;
+ " c+;
}
int )unto&&coordenada?() const
{
ret*rn D;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 47
int )unto&&coordenada@() const
{
ret*rn +;
}
Los atributos son accesibles desde cualquier mtodo asociado a la clase (es decir, definido dentro de su
mbito), como si fueran variables globales a todos ellos.
La implementacin de los mtodos miembro, por fuera de la clase, se puede incluir en el mismo archivo
de encabezado .h, donde se declara la clase, o en un archivo fuente .cpp separado.
Mtodos consultores
Como se vi en la declaracin y definicin de la clase E*nto, los mtodos de instancia coordenada?
y coordenada@, tenan la palabra reservada const al final de su declaracin:
int coordenada?() const;
int coordenada@() const;
Al declarar los mtodos de esta forma, se indica que son mtodos consultores. Los mtodos consultores,
son denominados as ya que slo consultan la informacin acerca del estado interno de los objetos sin
modificarlos.
Cuando un mtodo recibe por parmetro una referencia constante a un objeto slo podr invocar a los
mtodos consultores de dicho objeto.
Por ejemplo:
void )unto&&co*iar=(const E*nto U otroE*nto)
{
$$ 2rror 'e compilaci&n0 2l m_to'o invoca'o no respeta la re)erencia
$$ constante.
otroE*nto.car(ar@oor'ena'a(D +);
}
Constructores
Los objetos generalmente necesitan realizar operaciones durante su proceso de creacin, como por
ejemplo, inicializar variables o asignar memoria dinmicamente.
En el ejemplo anterior, si se define un objeto de tipo E*nto y se invoca a coordenada? antes de
determinar las coordenadas de dicho punto (mediante el mtodo cargar>oordenadas), se obtendr
un resultado indeterminado, ya que las variables D e + no fueron inicializadas correctamente.
Las clases cuentan con una funcin especial, denominada constructor, que lleva a cabo las operaciones
de inicializacin necesarias. El constructor es invocado automticamente cuando se crea un nuevo objeto
de una clase determinada; debe tener el mismo nombre que la clase y no retornar ningn valor.
Por ejemplo:
class E*nto
{
*ublic0
)unto();
void cargar>oordenadas(int cD int c+);
int coordenada?() const;
int coordenada@() const;
*rivate:
int D;
int +;
};
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 48
)unto&&)unto()
{
D " 0;
+ " 0;
}
En este caso, el constructor de la clase E*nto define un punto en el origen (0,0). De esta forma, cada
nuevo objeto creado contendr coordenadas inicializadas correctamente, evitando resultados
indeterminados.
Para crear un objeto utilizando este constructor:
E*nto p*nto; $$?in los par_ntesis ()
Constructores con argumentos
Al igual que todas las funciones del lenguaje, el constructor se puede sobrecargar, modificando el nmero
o tipo de los argumentos. El compilador determinar que constructor llamar de acuerdo a los parmetros
pasados en la creacin de los objetos. De esta forma, podemos definir un nuevo constructor, con dos
argumentos enteros, en reemplazo de la funcin cargar>oordenadas.
class E*nto
{
*ublic0
)unto();
)unto(int cD int D+);
int coordenada?() const;
int coordenada@() const;
*rivate:
int D;
int +;
};
)unto&&)unto()
{
D " 0;
+ " 0;
}
)unto&&)unto(int cD int c+)
{
D " cD;
+ " c+;
}
Para crear un objeto utilizando este nuevo constructor:
E*nto p(#2);
Si no se define un constructor, el compilador crear uno por defecto sin argumentos, que no realizar
ninguna accin. Sin embargo, si se define un constructor, el compilador ya no proveer un constructor por
defecto; por lo tanto, todas las instanciaciones de objetos debern utilizar dicho constructor respetando
los argumentos esperados.
Constructor por copia
Adems del constructor sin argumentos, el compilador define un constructor por copia por defecto si no
se ha definido uno.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 49
El constructor por copia crea un objeto a partir de otro existente. Este tipo de constructor slo tiene un
parmetro; una referencia constante a un objeto de la misma clase. El constructor por copia implcito
declarado por el compilador hace una asignacin simple atributo por atributo.
Para la clase E*nto, el constructor por copia por defecto es funcionalmente equivalente a:
)unto&&)unto(const E*nto U otroE*nto)
{
D " otroE*nto.D;
+ " otroE*nto.+;
}
Por lo tanto, el siguiente fragmento de cdigo es vlido:
E*nto pA(23);
E*nto p5(pA);
El constructor por copia se puede redefinir, modificando su implementacin, siempre que se respete su
interfaz. Para el ejemplo del punto esto no es realmente necesario porque todos los atributos son variables
simples.
Sin embargo, consideremos el caso de una clase con una estructura dinmica:
class /ector
{
*ublic0
Aector(unsigned int tam);
B
*rivate:
int T elementos;
unsigned int lon(it*';
};
Aector&&Aector(unsigned int tam)
{
elementos " ne% int 8tam:;
lon(it*' " tam;
}
Supongamos que quisiramos hacer una inicializacin de un vector a partir de otro:
/ector vA(10);
/ector v5(vA);
El estado resultante de la inicializacin de v5 no sera el esperado. Esto es porque el constructor por
copia por defecto realiza una asignacin simple del atributo elementos, y al tratarse de un puntero esto no
resulta adecuado. Veamos como sera el cdigo del constructor por defecto:
Aector&&Aector(const /ector U otro/ector)
{
elementos " otro/ector.elementos;
lon(it*' " otro/ector.lon(it*';
}
El comportamiento por defecto del constructor por copia hace que v5 quede haciendo referencia al
mismo bloque de memoria que vA. Esto es un problema grave que se debe resolver implementando el
constructor por copia de forma explcita, para que se comporte como esperamos:
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 50
class Aector
{
*ublic0
Aector(unsigned int tam);
Aector(const /ector U otro/ector);
B
*rivate:
int T elementos;
unsigned int lon(it*';
};
Aector&&Aector(const /ector U otro/ector)
{
elementos " ne% int 8otro/ector .lon(it*':;
lon(it*' " otro/ector.lon(it*';
for (int i " 0; i < lon(it*'; iPP)
elementos8i: " otro/ector.elementos8i:;
}
Destructor
El destructor es una funcin miembro especial, que se utiliza al eliminar un objeto de una clase
determinada. Al igual que el constructor, es una funcin que no se invoca explcitamente, sino que lo hace
el compilador automticamente cuando un objeto es destruido; ya sea porque se termin el mbito donde
estaba definido o porque es un objeto creado dinmicamente y se ha liberado su memoria, usando el
operador delete.
El destructor debe tener el mismo nombre de la clase, precedido por el smbolo ~. No recibe argumentos
ni retorna valores.
El uso principal de los destructores es liberar la memoria dinmica, que podra haber asignado el objeto
durante su tiempo de vida.
Por ejemplo, en el caso de la clase /ector, se define un destructor de la siguiente manera:
class /ector
{
*ublic0
B
CAector();
B
};
Aector&&CAector()
{
delete 8: elementos;
}
Sobrecarga de operadores
C++ permite utilizar los operadores clsicos, generalmente definidos para los tipos bsicos, para realizar
operaciones con objetos.
Por ejemplo, podramos definir el operador de comparacin por igual (==) para la clase E*nto. Esto
permitira conocer si dos puntos son iguales utilizando la siguiente sintaxis:
E*nto pA(23) p5(`-);
if (pA "" p5) {
]
}
Para sobrecargar un operador es necesario declarar las funciones operador, las cuales son como cualquier
otro mtodo, pero cuyo nombre se escribe utilizando la palabra reservada o*erator seguida del
operador que se quiere sobrecargar. La sintaxis general es:
<tipo!retorno> o*erator <opera'or> (<lista!'e!par3metros>);
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 51
Algunos de los operadores ms comunes que se pueden sobrecargar son:
+, -, *, /, =, <, >. >=, <= +=, -=, *=, /=, <<, >>, ==, !=, ++, , [], ()
Por ejemplo, para el caso del operador de comparacin por igual entre puntos:
class E*nto
{
*ublic0
B
bool o*erator""(const E*nto U p*nto) const;
B
};
bool )unto&&o*erator""(const E*nto U otroE*nto) const
{
return (D "" otroE*nto.D) UU (+ "" otroE*nto.+);
}
A continuacin se presenta una tabla con la declaracin necesaria para poder sobrecargar los operadores
ms importantes
12
(el smbolo @ se debe reemplazar por cada operador).
Expresin Operador Funcin miembro Funcin global
@a + - * ++ -- A::operator@() operator@(A)
a@ ++ -- A::operator@(int) operator@(A,int)
a@b + - * / < > == != <= >= << >> A::operator@ (B) operator@(A,B)
a@b = += -= *= /= [] A::operator@ (B) -
a(b, c...) ()
A::operator() (B,
C...)
-
Donde a es un objeto de la clase A, b es un objeto de la clase B y c es un objeto de la clase C.
La ltima columna indica que operadores pueden ser definidos como funciones globales, adems de como
funciones miembro.
Operador de salida de streams
Un ejemplo de un operador que generalmente se sobrecarga como una funcin global, es el operador de
salida de los streams de C++ (<<).
Por ejemplo, para imprimir directamente un objeto del tipo punto, pasndolo como argumento al utilizar
el cout, debemos definir la siguiente funcin que sobrecarga el operador correspondiente:
st'00ostream U o*erator (st'00ostream U sali'a const E*nto U p*nto)
{
sali'a <<.(.<< p*nto.coor'ena'aG() <<..<< p*nto.coor'ena'a^() <<.).;
return sali'a;
}
Lo cual permite escribir lo siguiente:
E*nto pA(23) p5(`-);
co*t << .E*nto A . << pA << .4n.;
co*t << .E*nto 5 . << p5 << .4n.;
12
Para ver una lista completa de los operadores que pueden ser sobrecargados: http://www.cplusplus.com/doc/tutorial/classes2/
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 52
Operador de asignacin
El operador de asignacin es el nico operador que se implementa por defecto. Sin embargo, es una buena
prctica siempre redefinir dicho operador cuando se define una clase nueva. Esto es porque la versin
implcita del operador se comporta de forma similar al constructor por copia por defecto. El mismo
tambin realiza una asignacin simple atributo por atributo, lo cual puede puede llevar al mismo tipo de
problemas que ya se indicaron.
Siguiendo el ejemplo de la clase /ector definiremos el operador de asignacin y lo aprovecharemos
para reimplementar el constructor por copia y as evitar la duplicacin de cdigo:
class /ector
{
*ublic0
Aector(const /ector U otro/ector);
/ector U o*erator"(const /ector U otro/ector);
B
};
Aector&&Aector(const /ector U otro/ector) {
elementos " 0;
o*erator"(otro/ector);
}
/ector U Aector&&o*erator"(const /ector U otro/ector) {
delete 8: elementos;
elementos " ne% int 8otro/ector.lon(it*':;
lon(it*' " otro/ector.lon(it*';
for (int i " 0; i < lon(it*'; iPP)
elementos8i: " otro/ector.elementos8i:;
return Tt"is;
}
La palabra reservada this
La palabra reservada t6is representa un puntero al objeto que est procesando el mensaje. A travs de
esta referencia se pueden acceder a las variables de instancia de las clases, en forma alternativa a la ya
observada. Esto es til cuando los parmetros ocultan a los atributos al coincidir sus nombres.
Un uso importante que tiene el parmetro implcito t6is es cuando se define el operador de asignacin.
En primer lugar el operador debe retornar una referencia al objeto que procesa el mensaje (el que est del
lado izquierdo de la asignacin). La nica forma de obtener dicha referencia es a travs del puntero
t6is, escribiendo *t6is.
En el mismo contexto del operador de asignacin, tambin se puede aprovechar el puntero t6is para
evitar asignar un objeto as mismo. En el caso particular de la clase /ector esto es fundamental; por lo
cual, el cdigo quedara de la siguiente forma:
/ector U Aector&&o*erator"(const /ector U otro/ector) {
if (t"is S" Uotro/ector) {
delete 8: elementos;
elementos " ne% int 8otro/ector .lon(it*':;
lon(it*' " otro/ector.lon(it*';
for (unsigned int i " 0; i < lon(it*'; iPP)
elementos8i: " otro/ector.elementos8i:;
}
return Tt"is;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 53
Clases parametrizadas
El mecanismo de plantillas o templates de C++ permite definir clases que reciben tipos como argumentos.
Podremos utilizar los tipos con los que se parametriza una clase, como si fueran tipos regulares a la hora
de definir los mtodos y atributos.
La sintaxis general de una clase parametrizada es la siguiente:
tem*late t2*ename <i'enti)ica'or> { t2*ename <i'enti)ica'or>}-
class <nombre!clase> {
B
};
La palabra clave t2*ename puede reemplazarse por class. Ambas son intercambiables.
La posibilidad de parametrizar clases es til cuando se estn definiendo tipos de datos cuya principal
funcin es contener otros objetos. Por ejemplo, consideremos el caso de la clase /ector, la cual se
defini previamente como un contenedor de enteros. Utilizando el mecanismo de plantillas podemos
redefinirlo para que almacene objetos de cualquier tipo:
tem*late<t2*ename 4> class /ector
{
*ublic0
Aector(unsigned int tam);
Aector(const /ector U otro/ector);
CAector();
/ector U o*erator"(const /ector U otro/ector);
4 U o*erator8:(unsigned int i);
bool e3iste(const 4 U elem) const;
*rivate:
4 T elementos;
unsigned int lon(it*';
};
tem*late<t2*ename 4> Aector4-&&Aector(unsigned int tam) {
elementos " ne% 4 8tam:;
lon(it*' " tam;
}
tem*late<t2*ename 4> Aector4-&&Aector(const /ector<4> U otro/ector) {
elementos " 0;
o*erator"(otro/ector);
}
tem*late<t2*ename 4> Aector4-&&CAector() {
delete 8: elementos;
}
tem*late<t2*ename 4> /ector<4> U Aector4-&&o*erator=(const /ector<4> U
otro/ector) {
if (t"is S" Uotro/ector) {
delete 8: elementos;
elementos " ne% 4 8otro/ector.lon(it*':;
lon(it*' " otro/ector.lon(it*';
for (unsigned int i " 0; i < lon(it*'; iPP)
elementos8i: " otro/ector.elementos8i:;
}
return Tt"is;
}
tem*late<t2*ename 4> 4 U Aector4-&&o*erator#$(unsigned int i) {
return elementos8i:;
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 54
tem*late<t2*ename 4> bool Aector4-&&e3iste(const 4 U elem) const {
bool encontra'o " false;
unsigned int i " 0;
%"ile (Sencontra'o UU (i < lon(it*')) {
if (elementos8i: "" elem)
encontra'o " true;
else
iPP;
}
return encontra'o;
}
Cuando se trabaja con clases parametrizadas, la implementacin de los mtodos se debe agregar en el
mismo archivo encabezado .h.
Ahora podemos definir un vector para que contenga enteros o cadenas de caracteres, a partir de la misma
definicin, como se puede a continuacin:
/ector<int> v(10);
/ector<strin(> 7(10);
for(int i"0; i<10; iPP)
v8i: " i;
for(int i"0; i<10; iPP) {
char aux[20];
s*rintf(a*D .Vi. i);
78i: " a*D;
}
co*t << v.eDiste(-) << .4n.;
co*t << 7.eDiste(.-.) << .4n.;
Que un tipo est parametrizado no significa que se pueda instanciar utilizando cualquier tipo de datos
como parmetro. La forma en la que estn implementados los mtodos impone ciertas restricciones sobre
los tipos que se podrn utilizar.
Por ejemplo, el mtodo eDiste de la clase /ector asume que el tipo utilizado como parmetro contar
con el operador de comparacin por igual (==). Si esto no es as, se producir un error de compilacin
que indicar este requerimiento implcito.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 55
Herencia
La herencia es un mecanismo fundamental de la programacin orientada a objetos que posibilita la
creacin de nuevas clases a partir de clases existentes.
La utilizacin de la herencia permite construir clasificaciones jerrquicas de clases, en donde cada clase
definir su funcionalidad y sus caractersticas propias, las cuales sern compartidas por todas las clases de
los niveles inferiores de la jerarqua. Estas clases, adems, extendern la funcionalidad de las clases
superiores modificando o agregando comportamiento.
La clase de la cual se hereda se denomina generalmente clase base, clase padre o superclase; mientras que
la clase que extiende a una clase base, se conoce como clase derivada, clase hija o subclase. Cada clase
derivada puede utilizarse como clase base para obtener una nueva clase derivada, y cada clase derivada
puede heredar funcionalidad de una o ms clases base (a esto se lo conoce como herencia mltiple).
La principal ventaja asociada a la utilizacin de herencia es la reutilizacin de cdigo. Al definir una
funcionalidad comn en una clase base, todas las clases derivadas compartirn dicha funcionalidad sin
duplicar cdigo, y con la posibilidad de modificar ese comportamiento definido. Tambin ayuda a
posibilitar que una aplicacin sea extensible, al permitir crear clases derivadas con las funcionalidades
que se desean aadir o redefinir.
Las principales complicaciones de utilizar herencia se deben al trabajo que hay que realizar para disear
correctamente las clases base, ya que cada cambio en dichas clases impactarn en todas las clases
derivadas.
Creacin de una clase derivada
La sintaxis general para definir una clase derivada es la siguiente:
class <nombre!clase!'eriva'a> & <nivel!acceso> <nombre!clase!base>
{ <nivel!acceso> <nombre!clase!base>} {
]
};
Como se ve, la herencia mltiple se puede realizar incluyendo ms de una clase base para la construccin
de una clase derivada.
En cuanto al nivel de acceso, las opciones posibles son:
*ublic: los miembros (atributos y mtodos) de la clase base conservan el nivel de acceso con el
cual fueron definidos.
*rotected: los miembros de la clase base que fueron definidos como pblicos son pasados al
nivel de acceso protegido. Esto restringe el acceso, desde fuera de la jerarqua, a los miembros
pblicos de la clase base si se intentan acceder mediante la clase derivada.
*rivate: es el nivel de acceso por defecto. En este caso todos los miembros de la clase base
pasan a ser privados en la clase derivada. Esto no permite que se acceda a los miembros de la
clase base, mediante la clase derivada, desde fuera de la jerarqua ni desde un nivel inferior al de
la clase derivada.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 56
Por ejemplo, definiendo la siguiente clase base:
class A
{
*ublic0
int variableA1;
void metodo=9();
*rotected0
int variableA2;
void metodo=:();
*rivate0
int variableA3;
void metodo=D();
};
De acuerdo al nivel de acceso que se utilice al hereder de esta clase, se presentarn tres casos distintos de
restricciones sobre sus miembros.
*ublic *rotected *rivate
class 5 0 *ublic A
{
>a clase 5 p*e'e acce'er a los
miembros pZblicos + prote(i'os
'e A.
*ublic0
void metodo59(){
variableA1PP;
}
};
class @ 0 *ublic 5
{
>a clase @ tambi_n p*e'e
acce'er a los miembros
pZblicos + prote(i'os 'e A.
]
};
int main()
{
=na instancia 'e 5 p*e'e
acce'er a los miembros
pZblicos 'e A + 5.
5 obKeto5;
obKeto5.meto'oA1();
obKeto5.variableA1;
obKeto5.meto'o51();
}
class 5 0 *rotected A
{
>a clase 5 p*e'e acce'er a los
miembros pZblicos + prote(i'os
'e A.
*ublic0
void metodo59() {
variableA1PP;
}
};
class @ 0 *ublic 5
{
>a clase @ tambi_n p*e'e
acce'er a los miembros
pZblicos + prote(i'os 'e A.
]
};
int main()
{
=na instancia 'e 5 no p*e'e
acce'er a los miembros
pZblicos 'e A solo a los
m_to'os pZblicos 'e 5.
5 obKeto5;
obKeto5.meto'o51();
}
class 5 0 *rivate A
{
>a clase 5 po'r3 acce'er a los
miembros pZblicos + prote(i'os
'e A.
*ublic0
void metodo59() {
variableA1PP;
}
};
class @ 0 *ublic 5
{
>a clase @ no po'r3 acce'er a
nin(Zn miembro 'e A.
]
};
int main()
{
=na instancia 'e 5 no p*e'e
acce'er a los miembros
pZblicos 'e A solo a los
m_to'os pZblicos 'e 5.
5 obKeto5;
obKeto5.meto'o51();
}
Despus de ver los ejemplos, se puede concluir que el nivel de acceso utilizado para heredar de la clase
base, es el nivel que se utilizar para restringir el acceso a todos los miembros de dicha clase, cuando se
invocan desde la clase derivada.
Constructores y destructores de las clases derivadas
Cuando se instancia un objeto de una clase derivada, primero se invoca al constructor de la clase base de
la cual extiende la clase en cuestin. Si la clase pertenece a una jerarqua de herencia de ms de un nivel
de extensin, los constructores de las clases base se invoca desde la clase de nivel superior en orden
descendente hasta llegar a la clase derivada. Por ltimo se invoca el constructor de la clase derivada.
En el caso del ejemplo visto anteriormente, al instanciar un objeto de la clase C, primero se llamar al
constructor de la clase A, luego al constructor de la clase B y por ltimo al constructor de la clase C.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 57
En el caso que el constructor de una clase base requiera el pasaje de algn parmetro para su invocacin,
estos parmetros debern ser pasados antes de inicializar los atributos de la clase derivada. Para esto se
utiliza la siguiente sintxis en la definicin del constructor de la clase derivada:
<nombre!clase!'eriva'a>({<lista!'e!par3metros>}) &
<nombre!clase!base>(<lista!'e!par3metros>)
{ <nombre!clase!base>(<lista!'e!par3metros>)} {
]
};
Por ejemplo, se define un constructor para la clase A que requiere un parmetro int. Si se desea invocar
a este constructor desde un constructor de la clase 5, se debe realizar de la siguiente forma:
class 5 0 *ublic A
{
*ublic0
5(int parametro1 int parametro2) 0 A(parametro1) {
}
};
En el caso de los destructores, el orden de invocacin es inverso al de los constructores. Es decir, primero
se invoca al destructor de la clase derivada, luego a los destructores de los objetos que formen parte de la
clase y, por ltimo, a los destructores de las clases base desde el nivel ms bajo al nivel superior.
Los constructores, los destructores y el operador de asignacin (=) son mtodos que no se herendan desde
la clase base a las clases derivadas; es decir, deben ser definidos especficamente en cada clase derivada o
sino el compilador se encargar de crearl sus versiones por defecto. La razn de esta diferencia con el
resto de los mtodos, que si se heredan automticamente, es porque se encargan de construir y destruir un
objeto, tareas que son especficas a cada clase particular.
Redefinicin de miembros en las clases derivadas
La definicin de un mtodo en una clase derivada, con igual nombre que algn otro mtodo existente en
una clase base, oculta la definicin de ese mtodo y todos los que tengan el mismo nombre. Esto se
conoce como redefinicin o superposicin (overriding) de un mtodo.
La nica forma de acceder al mtodo de la clase base que qued oculto es utilizando su nombre completo
(siempre que el nivel de acceso de la herencia lo permita):
<nombre!obKeto>.<nombre!clase!base>00<nombre!m_to'o>;
Por ejemplo:
class A
{
*ublic0
void *rocesar() {co*t << .Erocesar A.;};
void *rocesar(int valor);
};
class 5 0 *ublic A
{
*ublic0
void *rocesar(){co*t << .Erocesar 5.;};
};
int main () {
5 obKeto5;
obKeto5.procesar();
$$obKeto5.procesar(10); no es *na invocaci&n v3li'a.
obKeto5.A00procesar();
obKeto5.A00procesar(10);
}
Esta lgica de redefinicin no solo es vlida para los mtodos de una clase base sino tambin para todos
los atributos de clase que contenga.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 58
Polimorfismo
El polimorfismo es una de las propiedades ms importantes de la programacin orientada a objetos. Esta
propiedad indica que un programa puede trabajar con un objeto perteneciente a una clase sin importar de
qu clase concreta se trate.
En C++ el polimorfismo se aprovecha principalmente al utilizarlo junto a los mecanismos de punteros y
referencias. El lenguaje nos permite acceder a objetos de una clase derivada mediante un puntero o
referencia a una clase base. Obviamente, slo se podr acceder a los atributos y mtodos que hayan sido
definidos en la clase base.
Por ejemplo, si se define una funcin que reciba como parmetro una referencia a la clase base A, se
podr invocar con cualquier instancia de clases que hayan heredado de dicha clase:
void *roceso(A U a) {
a.procesar();
}
int main() {
5 obKeto5;
@ obKeto@;
proceso(obKeto5);
proceso(obKeto@);
}
En todos los casos, el mtodo invocado es el que est definido en la clase base, con lo cual la salida sera:
> Erocesar A
> Erocesar A
Una mejor forma de aprovechar el polimorfismo y la jerarqua de clases sera si, al invocar al mtodo
definido en la clase base, se ejecutaran las redefiniciones realizadas en las clases derivadas. De esta
forma, el comportamiento de un programa dependera de una instancia concreta que podra definirse en
tiempo de ejecucin, lo cual brindara una flexibilidad muy importante para el desarrollo de aplicaciones.
Esto se puede conseguir mediante lo que se conocen como mtodos virtuales.
Mtodos virtuales
Un mtodo virtual es bsicamente un mtodo de clase pero con la palabra reservada virtual al
comienzo de su declaracin.
virtual <tipo!retorno> <nombre!)*nci&n>(<lista!'e!par3metros>){{}};
Como se mencion, la caracterstica principal de los mtodos virtuales es que, cuando son invocados
mediante un puntero o referencia a una clase base, es la clase derivada la que responde el llamado
mediante su definicin del mtodo invocado.
Por ejemplo, si se cambia la definicin de la funcin vista en el ejemplo anterior:
class A
{
*ublic0
virtual void *rocesar() {co*t << .Erocesar A.;};
};

int main() {
5 obKeto5;
@ obKeto@;
proceso(obKeto5);
proceso(obKeto@);
}
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 59
Ahora la salida sera:
> Erocesar 5
> Erocesar @
Este ejemplo tambin se podra haber realizado con un puntero (*) en lugar de una referencia (&).
Una vez que un mtodo es declarado como virtual esta propiedad ser heredada en las clases derivadas,
por lo tanto, el mtodo seguir siendo virtual en estas clase. Si el mtodo definido como virtual en la clase
base, no se declara en las clases derivadas con el mismo tipo de valor de retorno, el mismo nmero y tipo
de parmetros que en la clase base, no se considerar como el mismo mtodo, sino como una redefinicin
o superposicin.
Una diferencia que es importante mencionar en este sentido, es que la sobrecarga se resuelve en tiempo de
compilacin utilizando los nombres de los mtodos y los tipos de sus parmetros; mientras que el
polimorfismo se resuelve en tiempo de ejecucin del programa en funcin de la clase a la que pertenece el
objeto en cuestin.
Con respecto a los constructores, para construir un objeto el constructor debe ser del mismo tipo que
dicho objeto, razn por la cual los constructores no pueden ser definidos como virtuales. Adems, si un
constructor llama a un mtodo virtual, ste siempre ser el de la clase base, debido a que el objeto de la
clase derivada an no ha sido creado.
Esta restriccin no se aplica a los destructores. Por el contrario, si una clase tiene como parte de su
interfaz mtodos virtuales, el destructor debe ser declarado virtual. Esto es debido a que cuando un
puntero a una clase base es destruido, se debe asegurar que se invoque el destructor de la clase derivada
correspondiente para que se realice la liberacin de recursos adecuado. Si un destructor no es declarado
como virtual, siempre que se destruyan objetos de clases derivadas, a travs de la clase base, slo se
realizarn las tareas definidas en el destructor de la clase base.
Clases abstractas
La creacin de mtodos virtuales posibilita la definicin de un nuevo tipo de clases denominadas clases
abstractas o incompletas. La utilizacin de este tipo de clases permite proveer un mecanismo, similar al
encontrado en otros lenguajes, conocido como interfaces.
La caracterstica distintiva de una clase abstracta es que no puede ser instanciada, s se pueden definir
punteros y referencias. Para definir una clase abstracta solamente es necesario definir uno de sus mtodos
como virtual puro.
virtual <tipo!retorno> <nombre!)*nci&n>(<lista!'e!par3metros>) " 0;
Por ejemplo:
class A
{
*ublic0
virtual void *rocesar() " 0;
};
Todas las clases que hereden de la clase A estarn obligadas a definir el mtodo *rocesar para poder
ser instanciadas, sino seguirn siendo clases abstractas.
Notas del Lenguaje C++. Anlisis y Diseo de Algoritmos. Pgina 60

You might also like