Sei sulla pagina 1di 12

C++ con Clase

Curso de C++
Curso de C++
Estilo:

Normal

Activar

Visitas desde 2000-09-09


Usuarios en lnea

Con Clase

C++

Win API 32

HTML y CSS

Grficos

MySQL
Artculos

Listas
<<

<

>

>>

Curso

Info

Bibliotecas

Tabla

Comentario

o
o
o
o
o

Introduccin
1 Toma de contacto
2 Tipos de variables I
3 Funciones I
4 Operadores I
5 Sentencias
6 Declaracin de variables
7 Notacin
8 Cadenas de caracteres
9 Conversin de tipos
10 Variables II: Arrays
11 Objetos III: Estructuras
12 Objetos IV: Punteros 1
13 Operadores II
14 Oper III: Precedencia
15 Funcs II: valor y referencia
16 Variables V: Uniones
17 Variables VI: Punteros 2
18 Operadores IV
19 Definicin de tipos
20 Funciones III: ms cosas
21 Funciones IV: Sobrecarga
22 Operadores V: Sobrecarga
23 El preprocesador
Directiva #define
Directiva #undef
Directivas condicionales
Directivas #ifdef, #ifndef
Directiva #error

o
o
o
o

Directiva #include
Directiva #line
Directiva #pragma
Directiva #warning
24 Funciones V: Recursividad
25 Vbls VII: Almacenamiento
26 Espacios con nombre
27 Clases I: definiciones
28 Declaracin de una clase
29 Constructores
30 Destructores
31 El puntero this
32 Sistema de proteccin
33 Modificadores
34 Ms sobre las funciones
35 Operadores sobrecargados
36 Herencia
37 Funciones virtuales
38 Derivacin mltiple
39 Trabajar con ficheros
40 Plantillas
41 Punteros a miembros
42 Castings en C++
43 Manejo de excepciones
A Codificacin ASCII
B Palabras reservadas
C Bibliotecas estndar
D Trigrafos y smbolos alt.
E Streams

23 El preprocesador
^

El preprocesador analiza el fichero fuente antes de la fase de compilacin real, y


realiza las sustituciones de macros y procesa las directivas del preprocesador. El
preprocesador tambin elimina los comentarios.
Una directiva de preprocesador es una lnea cuyo primer carcter es un #.
A continuacin se describen las directivas del preprocesador, aunque algunas ya las
hemos visto antes.

Directiva #define
La directiva #define, sirve para definir macros. Las macros suministran un
sistema para la sustitucin de palabras, con y sin parmetros.
^

Sintaxis:
#define identificador_de_macro <secuencia>

El preprocesador sustituir cada ocurrencia del identificador_de_macro en el


fichero fuente, por la secuencia. Aunque como veremos, hay algunas excepciones.
Cada sustitucin se conoce como una expansin de la macro. La secuencia es
llamada a menudo cuerpo de la macro.
Si no se especifica una secuencia, el identificador_de_macro sencillamente, ser
eliminado cada vez que aparezca en el fichero fuente.
Despus de cada expansin individual, se vuelve a examinar el texto expandido a la
bsqueda de nuevas macros, que sern expandidas a su vez. Esto permite la
posibilidad de hacer macros anidadas. Si la nueva expansin tiene la forma de una
directiva de preprocesador, no ser reconocida como tal.

Existen otras restricciones a la expansin de macros:


Las ocurrencias de macros dentro de literales, cadenas, constantes alfanumricas o
comentarios no sern expandidas.
Una macro no ser expandida durante su propia expansin, as #define A A, no ser
expandida indefinidamente.
No es necesario aadir un punto y coma para terminar una directiva de
preprocesador. Cualquier carcter que se encuentre en una secuencia de macro,
incluido el punto y coma, aparecer en la expansin de la macro. La secuencia
termina en el primer retorno de lnea encontrado. Las secuencias de espacios o
comentarios en la secuencia, se expandirn como un nico espacio.

Directiva #undef
^

Sirve para eliminar definiciones de macros previamente definidas. La definicin de


la macro se olvida y el identificador queda indefinido.
Sintaxis:
#undef identificador_de_macro

La definicin es una propiedad importante de un identificador. Las directivas


condicionales #ifdef e #ifndef se basan precisamente en esta propiedad de los
identificadores. Esto ofrece un mecanismo muy potente para controlar muchos
aspectos de la compilacin.
Despus de que una macro quede indefinida puede ser definida de nuevo
con #define, usando la misma u otra definicin.
Si se intenta definir un identificador de macro que ya est definido, se producir un
aviso, un warning, si la definicin no es exactamente la misma. Es preferible usar
un mecanismo como este para detectar macros existentes:
#ifndef NULL
#define NULL 0L
#endif

De este modo, la lnea del #define se ignorar si el smbolo NULL ya est definido.

Directivas #if, #elif, #else y #endif


^

Permiten hacer una compilacin condicional de un conjunto de lneas de cdigo.


Sintaxis:
#if expresin-constante-1
<seccin-1>
#elif <expresin-constante-2>
<seccin-2>
.
.
.
#elif <expresin-constante-n>
<seccin-n>
<#else>
<seccin-final>
#endif

Todas las directivas condicionales deben completarse dentro del mismo fichero.
Slo se compilarn las lneas que estn dentro de las secciones que cumplan la
condicin de la expresin constante correspondiente.
Estas directivas funcionan de modo similar a los operadores condicionales C++. Si
el resultado de evaluar la expresin-constante-1, que puede ser una macro, es
distinto de cero (true), las lneas representadas por seccin-1, ya sean lneas de
comandos, macros o incluso nada, sern compiladas. En caso contrario, si el
resultado de la evaluacin de la expresin-constante-1, es cero (false), la seccin-1
ser ignorada, no se expandirn macros ni se compilar.
En el caso de ser distinto de cero, despus de que la seccin-1 sea preprocesada, el
control pasa al #endif correspondiente, con lo que termina la secuencia
condicional. En el caso de ser cero, el control pasa al siguiente lnea #elif, si existe,
donde se evaluar la expresin-constante-2. Si el resultado es distinto de cero, se
procesar la seccin-2, y despus el control pasa al correspondiente #endif. Por el
contrario, si el resultado de la expresin-constante-2 es cero, el control pasa al
siguiente #elif, y as sucesivamente, hasta que se encuentre un #else o un #endif.
El #else, que es opcional, se usa como una condicin alternativa para el caso en
que todas la condiciones anteriores resulten falsas. El #endif termina la secuencia
condicional.
Cada seccin procesada puede contener a su vez directivas condicionales, anidadas
hasta cualquier nivel, cada #if debe corresponderse con el #endifms cercano.
El objetivo de una red de este tipo es que slo una seccin, aunque se trate de una
seccin vaca, sea compilada. Las secciones ignoradas slo son relevantes para
evaluar las condiciones anidadas, es decir asociar cada #if con su #endif.
Las expresiones constantes deben poder ser evaluadas como valores enteros.

Directivas #ifdef e #ifndef


Estas directivas permiten comprobar si un identificador est o no actualmente
definido, es decir, si un #define ha sido previamente procesado para el
identificador y si sigue definido.
^

Sintaxis:
#ifdef <identificador>
#ifndef <identificador>

La lnea:
#ifdef identificador

tiene exactamente el mismo efecto que


#if 1

si el identificador est actualmente definido, y el mismo efecto que


#if 0

si el identificador no est definido.


#ifndef comprueba la no definicin de un identificador, as la lnea:

#ifndef identificador

tiene el mismo efecto que


#if 0

si el identificador est definido, y el mismo efecto que


#if 1

si el identificador no est definido.


Por lo dems, la sintaxis es la misma que para #if, #elif, #else, y #endif.
Un identificador definido como nulo, se considera definido.

Directiva #error
^

Esta directiva se suele incluir en sentencias condicionales de preprocesador para


detectar condiciones no deseadas durante la compilacin. En un funcionamiento
normal estas condiciones sern falsas, pero cuando la condicin es verdadera, es
preferible que el compilador muestre un mensaje de error y detenga la fase de
compilacin. Para hacer esto se debe introducir esta directiva en una sentencia
condicional que detecte el caso no deseado.
Sintaxis:
#error mensaje_de_error

Esta directiva genera el mensaje:


Error: nombre_de_fichero n_lnea : Error directive: mensaje_de_error

Este ejemplo est extrado de uno de los ficheros de cabecera del compilador GCC:
#ifndef BFD_HOST_64_BIT
#error No 64 bit integer type available
#endif /* ! defined (BFD_HOST_64_BIT) */

Directiva #include
La directiva #include, como ya hemos visto, sirve para insertar ficheros externos
dentro de nuestro fichero de cdigo fuente. Estos ficheros son conocidos como
ficheros incluidos, ficheros de cabecera o "headers".
^

Sintaxis:
#include <nombre de fichero cabecera>
#include "nombre de fichero de cabecera"
#include identificador_de_macro

El preprocesador elimina la lnea #include y, conceptualmente, la sustituye por el


fichero especificado. El tercer caso haya el nombre del fichero como resultado de
aplicar la macro.
El cdigo fuente en si no cambia, pero el compilador "ve" el fichero incluido. El
emplazamiento del #include puede influir sobre el mbito y la duracin de
cualquiera de los identificadores en el interior del fichero incluido.

La diferencia entre escribir el nombre del fichero entre "<>" o """", est en el
algoritmo usado para encontrar los ficheros a incluir. En el primer caso el
preprocesador buscar en los directorios "include" definidos en el compilador. En el
segundo, se buscar primero en el directorio actual, es decir, en el que se encuentre
el fichero fuente, si no existe en ese directorio, se trabajar como el primer caso.
Si se proporciona el camino como parte del nombre de fichero, slo se buscar es el
directorio especificado.

Directiva #line
^

No se usa, se trata de una caracterstica heredada de los primitivos compiladores C.


Sintaxis:
#line constante_entera <"nombre_de_fichero">

Esta directiva se usa para sustituir los nmeros de lnea en los programas de
referencias cruzadas y en mensajes de error. Si el programa consiste en secciones de
otros ficheros fuente unidas en un slo fichero, se usa para sustituir las referencias
a esas secciones con los nmeros de lnea del fichero original, como si no se hubiera
integrado en un nico fichero.
La directiva #line indica que la siguiente lnea de cdigo proviene de la lnea
"constante_entera" del fichero "nombre_de_fichero". Una vez que el nombre de
fichero ha sido registrado, sucesivas apariciones de la directiva #line relativas al
mismo fichero pueden omitir el argumento del nombre.
Las macros sern expandidas en los argumentos de #line del mismo modo que en
la directiva #include.
La directiva #line se us originalmente para utilidades que producan como salida
cdigo C, y no para cdigo escrito por personas.

Directiva #pragma
^

Sintaxis:
#pragma nombre-de-directiva

Con esta directiva, cada compilador puede definir sus propias directivas, que no
interferirn con las de otros compiladores. Si el compilador no reconoce el nombrede-directiva, ignorar la lnea completa sin producir ningn tipo de error o
warning.
Teniendo lo anterior en cuenta, veamos una de las directivas pragma ms
extendidas en compiladores, pero teniendo en cuenta que no tienen por qu estar
disponibles en el compilador que uses.
Tampoco es bueno usar estas directivas, ya que suelen hacer que el cdigo no sea
portable, es mejor buscar alternativas.
Directiva #pragma pack()

Esta directiva se usa para cambiar la alienacin de bytes cuando se declaran objetos
o estructuras.
Recordemos lo que nos pasaba al aplicar el operador sizeof a estructuras con el
mismo nmero y tipo de campos, aunque en distinto orden.

Algunas veces puede ser conveniente alterar el comportamiento predefinido del


compilador en lo que respecta al modo de empaquetar los datos en memoria. Por
ejemplo, si tenemos que leer un objeto de una estructura y con un alineamiento
determinados, deberemos asegurarnos de que nuestro programa almacena esos
objetos con la misma estructura y alineamiento.
La directiva #pragma pack() nos permite alterar ese alineamiento a voluntad,
indicando como parmetro el valor deseado. Por ejemplo:
#include <iostream>
using namespace std;
#pragma pack(1)
struct A {
int x;
char a;
int y;
char b;
};
#pragma pack()
struct B {
int x;
int y;
char a;
char b;
};
int main()
cout <<
<<
cout <<
<<
cout <<
<<
cout <<
<<

{
"Tamao de int: "
sizeof(int) << endl;
"Tamao de char: "
sizeof(char) << endl;
"Tamao de estructura A: "
sizeof(A) << endl;
"Tamao de estructura B: "
sizeof(B) << endl;

return 0;
}

La salida, en este caso es:


Tamao
Tamao
Tamao
Tamao

de
de
de
de

int: 4
char: 1
estructura A: 10
estructura B: 12

Vemos que ahora la estructura A ocupa exactamente lo mismo que la suma de los
tamaos de sus componentes, es decir, 10 bytes.
Esta directiva funciona como un conmutador, y permanece activa hasta que se
cambie el alineamiento con otra directiva, o se desactive usando la forma sin
parmetros.

Pero existe una alternativa, aparentemente ms engorrosa, pero ms portable.


Atributos

Se pueden especificar ciertos atributos para todas las variables, ya sea en la


declaracin de tipos o en la declaracin de los objetos.
Para ello se usa la palabra __attribute__, que admite varios parmetros:

__aligned__ que permite especificar el nmero del que tiene que se


mltiplo la direccin de memoria.

__packed__ que permite especificar el formato empaquetado, es


decir, el alineamiento sera de un byte.

Por ejemplo:
struct __attibute__((__packed__)) A {
int x;
char a;
int y;
char b;
};

Esta forma tiene el mismo efecto que el ejemplo anterior, pero tiene algunas
ventajas.
Para empezar, se aplica slo a la estructura, unin o clase especificada. Adems, nos
aseguramos de que o bien el compilador tiene en cuenta este atributo, o nos da un
mensaje de error. Con la directiva #pragma, si el compilador no la reconoce, la
ignora sin indicar un mensaje de error.
El otro atributo, __aligned__ requiere un nmero entero como parmetro, que es
el nmero del que las direcciones de memoria han de ser mltiplos:
struct __attibute__((__aligned__(4))) A {
int x;
char a;
int y;
char b;
};

Directiva #warning
^

Sintaxis:
#warning mensaje_de_aviso

Sirve para enviar mensajes de aviso cuando se compile un fichero fuente C o C++.
Esto nos permite detectar situaciones potencialmente peligrosas y avisar al
programador de posibles errores.
Este ejemplo est extrado de uno de los ficheros de cabecera del compilador GCC:
#ifdef __DEPRECATED
#warning This file includes at least one deprecated or antiquated
header. \

Please consider using one of the 32 headers found in section


17.4.1.2 of the \
C++ standard. Examples include substituting the <X> header for the
<X.h> \
header for C++ includes, or <iostream> instead of the deprecated
header \
<iostream.h>. To disable this warning use -Wno-deprecated.
#endif

Aprovecho para comentar que una lnea en el editor se puede dividir en varias
aadiendo el carcter '\' al final de cada una. En el ejemplo anterior, todo el texto
entre la segunda y la sexta lnea se considera una nica lnea por el compilador.
[ Arriba ] [ Operadores ] [ Entradas y salidas ] [ Decl. y def. ]

Por Alberto
Valero para la
Web del
Programador

TRABAJANDO CON FUNCIONES


DECLARACIN Y DEFINICIN DE FUNCIONES
En C++ hay que distinguir entre lo que es un declaracin y una definicin de una funcin. En la
declaracin de una funcin tan slo se incluye la cabecera o prototipo de la misma, y siempre tiene que
aparecer antes de ser utilizada. En la definicin de la funcin aparecen las sentencias que ejecuta dicha
funcin, y puede aparecer en cualquier parte del programa. Se puede realizar la declaracin y la
definicin al mismo tiempo, pero como veremos ms adelante, no es una prctica habitual.
La declaracin de una funcin tiene la siguiente sintaxis:

tipo_devuelto

nombre_funcin (parmetros);

Y la mejor manera de verlo es con un ejemplo:


float integral(float , float);
sta sera la declaracin o prototipo de una funcin llamada que que devolver un tipo real y a su vez
tomar como parmetros dos reales, en la declaracin no es necesario indicar como se llaman.
Cuando no queremos que una funcin nos devuelva un valor o que tenga parmetros, utilizaremos el
tipo void. Es decir, una funcin que no devolviera nada y no tomara parmetros se declarara de la
siguiente manera:

void ejemplo (void);


Si bien, en la mayora de los compiladores podramos prescindir de ello poniendo en la declaracin
simplemente:
ejemplo ( );
Las funciones, al igual que las variable, admiten el tipo de almacenamiento extern, quiere decir
esto, que las podramos definir en un archivo en utilizarlas en otro sin ms que utilizar la palabra
reservada extern en su declaracin.
Es siguiente paso ser definir la funcin, para ello repetimos el prototipo de la funcin (en este
caso si es necesario introducir el nombre de los parmetros) y a continuacin y entre llaves el cuerpo de

la misma, en el que podremos utilizar todo lo visto hasta ahora (declaracin de variables, bucles,
sentencias de control de la lgica, etc.) La manera de utilizar variables o llamar a otras funciones sigue
la misma lgica que en turbo pascal, Podremos utilizar variables globales o variables locales definidas en
la funcin, y podremos llamar a todas la funciones que haya sido previamente declaradas (ojo no es
necesario que hayan sido definidas).
El valor que devuelve la funcin lo indicaremos en el cuerpo de la misma con la palabra
reservada return valor;
Veamos un programa ejemplo que aplique todo esto:

#include<iostream.h>
int factorial(int); //declaramos la funcin factorial.
main( )
//funcin principal del programa.
{
cout<<"Introduce un nmero del que quieras hallar el factorial";
int i;
cin>>i;
cout << "El factorial de " << i << " es: "<< factorial(i);
}
int factorial(int a)
//Ahora definimos la funcin factorial.
{
int aux;
for (int i=1; i<=a; i++)
{
aux = aux*i;
}
return aux;
//valor que devuelve la funcin
}
LA FUNCIN MAIN
Todos los programas en C++ tienen un punto de entrada al programa denominado main(). Esto quiere
decir, que cuando compilamos un programa y lo ejecutamos, el programa buscar el conjunto de
rdenes que vienen dadas pos las sentencias de la funcin main(), y por lo tanto est ser
imprescindible en cualquier programa escrito en C++.
Para nosotros de momento la funcin main no tomar parmetros ni devolver nada, por lo que su
cabecera ser void main(void).
ARGUMENTOS POR OMISIN EN UNA FUNCIN
Todos los parmetros formales de una funcin, o bien algunos de ellos (desde un determinado
parmetro hasta el final), se pueden declarar por omisin. Es decir en la declaracin de la funcin o en
su definicin se especificarn los valores que deberan asumir los parmetros cuando se produzca una
llamada a la funcin y se omitan los mismos para tales parmetros. Por ejemplo, imaginemos la funcin
factorial antes utilizada,
int factorial (int a=10) //definimos el valor por defecto de a en 10.
{
...
}
main( )
{

cout<< factorial ( );
}
Mostrara por pantalla el factorial de 10, ya que no le hemos pasado ningn parmetro (si le
passemos alguno, evidentemente calculara el factorial del parmetro que le passemos.
FUNCIONES EN LNEA
Cuando una funcin se califica en lnea (incline) el compilador tiene la facultad de reemplazar
cualquier llamada a la funcin en el programa fuente, por el cuerpo actual de la funcin. Quiere decir
esto, que el compilador puede tomar la iniciativa de no expandir la funcin, por ejemplo, por ser
demasiado larga.
Con esto conseguimos que el compilador inserte el cdigo de la funcin compilada en el ejecutable cada
vez que la llamemos. Si la funcin se utiliza, por ejemplo diez veces, entonces el cdigo de esa funcin
aparece en el programa diez veces, en lugar de slo una vez, como es el caso de una funcin estndar.
Esta propiedad de C++ reduce el tiempo de ejecucin de los programas, pero aumenta
considerablemente el tamao de los mismos.
La declaracin de las funciones en lnea se hace anteponiendo la palabra inline.
inline int factorial (int a)
Las funciones en lnea si que deben haber sido definidas antes de su utilizacin.
FUNCIONES SOBRECARGADAS
La sobrecarga de funciones es una caracterstica de C++ que hace los programas ms legibles. Consiste
en que un conjunto de funciones que realizan la misma tarea o una tarea muy similar tengan el mismo
nombre, que tal manera que en funcin de los parmetros que le pasemos el compilador sepa en cada
momento cual de ellas debe utilizar.
Por ejemplo, supongamos una funcin llamada suma, esta deber ser diferente si queremos sumar
complejos, de otra en la que queramos sumar enteros, pues bien, en C++ se pueden utilizar dos
funciones llamadas suma como sigue...
typedef complejo int[2]
int suma (int a, int b)
{
return (a+b)
}
complejo suma (complejo a, complejo b)
{
complejo aux;
aux[1]=a[1] + b[1];
aux[2]=a[2]+b[2];
return aux;
}
Hemos definido un tipo de dato que ser complejo formado por un vector de dos elementos, entonces,
si al llamar a la funcin, le pasamos como parmetros dos enteros nos ejecutar el cuerpo de la funcin
que hemos definido primero y en caso de que le pasemos dos variables de tipo complejo ejecutar la
segunda.
Todas las posibilidades que hemos visto hasta ahora de trabajar con funciones, obviamente se pueden
mezclar unas con otras, es decir podramos definir perfectamente dos funciones sobrecargadas que

tomarn parmetros por defecto.

Potrebbero piacerti anche