06 Programacion en C++

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 47

3 Identificacin del endianness del sistema

Si estamos escribiendo una aplicacin o librera muy general, que en algn punto deba tener en
cuenta el endiannes de la mquina anfitriona, es posible averiguarlo fcilmente mediante una
directiva que podemos utilizar posteriormente en las sentencias correspondientes segn el
resultado. Seran las siguientes:
const unsigned int myOne = 1;
#define IS_BIGENDIAN (*(char*)(&myOne) == 0)
#define IS_LITTLEENDIAN (*(char*)(&myOne) == 1)
Observe que la direccin de myOne (que es un puntero-a-int) es convertida a puntero-a-
char mediante el cast correspondiente; a continuacin se compara el contenido de esta direccin
con cero y con 1. En realidad se est comparando el primer bite de myOne. El truco est
precisamente en comparar el contenido del primer byte (la comparacin myOne == 1 sera
siempre cierta). El resultado es 0 (falso) o 1 (cierto) segn el modelo del sistema utilizado, que
corresponder o no, con el del hardware subyacente segn el caso. Por ejemplo, en una mquina
Intel&Windows, el programa
#include <cstdlib>
#include <iostream>

const unsigned int myOne = 1;
#define IS_BIGENDIAN (*(char*)(&myOne) == 0)
#define IS_LITTLEENDIAN (*(char*)(&myOne) == 1)

int main(int argc, char *argv[]) {
std::cout << "Esta maquina es Big-endian: " <<
(IS_BIGENDIAN? "Cierto" : "Falso") << std::endl;
std::cout << "Esta maquina es Little-endian: " <<
(IS_LITTLEENDIAN? "Cierto" : "Falso") << std::endl;

system("PAUSE");
return EXIT_SUCCESS;
}
Produce la siguiente salida:
Esta maquina es Big-endian: Falso
Esta maquina es Little-endian: Cierto
Presione cualquier tecla para continuar . . .

3. Elementos lxicos
"In the software professions reading is like breathing. Stopping can be
dangerous to your health". David Weber C/C++ Users Journal. Marzo 1996
"Twho C++ tutorials".
1 Sinopsis
Los elementos que componen el lenguaje C++, los podemos dividir en dos grandes grupos:
Comentarios, que como veremos son eliminados por el preprocesador ( 3.1).
Tokens, una serie de palabras que constituyen el lenguaje que realmente entiende el
compilador. Dentro de este grupo, el lenguaje C++ distingue cinco tipos distintos de palabras:
Palabras clave (keywords). Son palabras reservadas por el lenguaje para propsitos
especiales, y no deben ser utilizadas como identificadores ( 3.2.1).
Identificadores, tambin llamados etiquetas. Son nombres arbitrarios de cualquier longitud
que sirven para identificar los objetos ( 3.2.2).
Constantes: Datos que estn definidos en el programa y que no pueden ser modificados a lo
largo del mismo ( 3.2.3).
Operadores. Un tipo de tokens que pueden aparecer en las expresiones, e indican al
compilador la realizacin de determinadas operaciones matemticas ( 4.9).
Puntuadores. Signos de puntuacin, anlogos a los utilizados en el lenguaje corriente (
3.2.6).

3.1 Comentarios
"Remember, comments are for humans, so write them that way!". Aaron
Weiss. "JavaScript Tutorial for Programmers".
1 Sinopsis
Comentarios son anotaciones; observaciones, recordatorios, etc. en el programa. Son para uso
exclusivo del programador, y eliminados del cdigo fuente en la fase de preprocesado; antes
del anlisis sintctico ( 1.4).
Aparte de las consideraciones estrictamente formales que se indican en esta seccin, no debemos
perder de vista que los comentarios, aunque voluntarios (no es obligatorio escribirlos), representan
una ayuda inestimable durante la construccin del programa. Siendo imprescindibles para el
programador original, o los que le sucedan en las tareas de mantenimiento, cuando es necesario
habrselas con el cdigo un tiempo despus de que fue escrito. Adems de clarificar ideas, los
comentarios son tambin un valioso instrumento de depuracin, pues permiten eliminar
provisionalmente secciones enteras de cdigo.
En C++ coexisten dos formas de comentarios: El de C clsico y el de C++. Ambos son soportados
por C++Builder, que tiene adems una extensin particular sobre el estndar ANSI, los
comentarios anidados (este ltimo tipo solo debe usarse si la compatibilidad no es importante).
Tambin deben tenerse en cuenta las observaciones que siguen sobre el uso de separadores
(whitespaces) y delimitadores en los comentarios para evitar otros problemas de compatibilidad.
2 Comentarios C
Un comentario C es cualquier secuencia de caracteres contenida entre los delimitadores /* ...
*/. La totalidad de la secuencia, incluyendo los delimitadores /* y */ son sustituidos por un
simple espacio despus de la expansin de macros (algunas implementaciones de C pueden
eliminar los comentarios sin reemplazarlos por espacios).
Ejemplo:
int x = 2; /* esto es un comentario que ser eliminado o sustituido
por un simple espacio despus en la frase de preprocesado. Como puede
verse, el comentario puede ocupar varias lneas de texto en el cdigo
fuente.
Se recomienda utilizarlos con profusin, a veces todas las explicaciones
son pocas, ya que el C++ es un lenguaje bastante crptico en algunas
ocasiones, sobre todo algunas sentencias muy "elegantes" y comprimidas,
pero ininteligibles en una primera lectura */
Ejemplo; la expresin:
int /* declaracin */ i /* contador */;
es analizada sintcticamente como estos tres tokens: int i y ;
3 Pegado de cadenas
Algunos compiladores C clsicos utilizan el smbolo /**/ para el pegado (concatenado) de tokens,
pero el nuevo Estndar ANSI recomienda que esto se haga con ## (ver ejemplos).
El pegado de tokens es una tcnica que utiliza las habilidades de preprocesador para construir
nombres nuevos utilizando macros ( 4.9.10b). Por ejemplo:
#define VAR(i,j) (i/**/j) // Incorrecto
#define VAR(i,j) (i##j) // Correcto
#define VAR(i,j) (i ## j) // Correcto

Despus de estas macros, las expresiones que siguen son transformadas por el preprocesador
como se indica
int VAR(opcion, uno)( ); int opcionuno();
int VAR(opcion, dos)( ); int opciondos();
int VAR(opcion, tres)( ); int opciontres();
4 Comentarios C++
C++ admite comentarios de una sola lnea utilizando dos barras inclinadas ( // ) como seal de
comienzo. El comentario empieza en este punto (incluyendo las seales de comienzo) y contina
hasta el prximo carcter de nueva linea.
class X { // esto es un comentario
...
};
5 Comentarios anidados
El estndar ANSI C no permite la existencia de comentarios anidados [1]. Por ejemplo, no
podemos utilizar el comentario:
/* int /* declaracin */ i /* contador */; */
porque el mbito del primer /* termina en el primer */, por lo que se obtiene: i; */, lo que
producira un error de sintaxis.
6 Delimitadores y espacios
En casos raros, algunos espacios antes de /*; //, y despus de */, aunque no sean
sintcticamente imprescindibles, deben ponerse para evitar posibles problemas de
portabilidad. Por ejemplo, en este cdigo:
int i = j//* divide por k*/k;
+m;
es analizado sintcticamente como
int i = j +m;
no como:
int i = j/k;
+m;
que sera lo esperado segn las reglas de C. La forma que sigue (ms legible) evitara este
problema.
int i = j/ /* divide por k */ k;
+m;


3.2 Tokens
1 Sinopsis
El tratar de la estructura lgica de un programa ( 1.3.1) se seal que tokens son los elementos
en que el preprocesado desmenuza el cdigo fuente. En un lenguaje de programacin, los tokens
son el equivalente a las palabras y signos de puntuacin en el lenguaje natural escrito. Los tokens
estn separados por elementos de separacin que reciben el nombre genrico de separadores (
1.4).
Comprenden los siguientes tipos de elementos (podramos considerar que el lenguaje
computacional C++ tiene las siguientes clases de "palabras"):
Palabras clave ("keywords"). C++ dispone de un conjunto relativamente extenso de
palabras clave, sealadas en ( 3.2.1).
Identificadores. Su nmero puede ser virtualmente infinito; dentro de ciertas normas el
programador es libre de elegir los que mejor se ajusten a sus necesidades.( 3.2.2).
Constantes. Existen varias clases, cuyos detalles se exponen en las pginas siguientes (
3.2.3)
operadores ( 4.9)
signos de puntuacin, tambin llamados puntuadores ( 3.2.6).

En ocasiones, los operadores y signos de puntuacin comparten la misma representacin
escrita. En estos casos, el sentido debe deducirse del contexto y por la forma en que estn
agrupados los diversos signos.
El conjunto de smbolos; grupos de smbolos, y palabras utilizados en C++ como operadores y/o
puntuadores, es el siguiente (los operadores se han sealado en azul):
{ } [ ] # ## ( ) \
<: :> <% %> %: %:%: ; : ...
" ' ? :: . .*
+ - * / % ^ & | ~
! = < > += -= *= /= %=
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- , ->* ->
and and_eq bitand bitor compl not not_eq or or_eq
xor xor_eq ( ) [ ] new delete new[ ] delete[ ]


Una vez entregado el fuente al compilador, es precisamente el analizador sintctico ("parser") el
encargado de es identificar los tokens. Por ejemplo, la sentencia
int i; float f;
es descompuesta por el "parser" en los siguientes tokens:
int palabra clave
i identificador
; puntuador
float palabra clave
f identificador
; puntuador

3.2.1 Palabras clave
1 Sinopsis
Las palabras clave ("Keywords") son identificadores utilizados por el lenguaje para fines
especiales, y no pueden ser utilizadas como identificadores (por esta razn se suelen denominar
tambin palabras reservadas). Por ejemplo, no pueden ser utilizadas como nombres de variables,
clases o funciones.
El primitivo C de Kerningham y Ritchie tena solo 27; el C estndar las ampli a 32, y C++ aadi
algunas ms. Hay que advertir que aunque el Estndar C++ define perfectamente cuales son las
palabras reservadas, incluidas a continuacin, los compiladores pueden incluir algunas otras por su
cuenta, que son por tanto dependientes de la plataforma.
Nota: recordar que el compilador C++Builder dispone de una opcin -A de compilacin (
1.4.3) que permite forzar las reglas a ANSI C++ estricto, con el fin de conseguir un cdigo
lo ms portable posible. Con esta opcin, las palabras clave no estrictamente ANSI son
ignoradas como tales. El resto de compiladores (MS Visual y GCC) tienen opciones similares.
2 Palabras clave del C++ Estndar

Keyword referencia Keyword referencia Keyword referencia
asm 4.10 and 4.9.8 and_eq 4.9.8
auto 4.1.8a bitand 4.9.8 bitor 4.9.8
bool 3.2.1b break 4.10.4 case 4.10.2
catch 1.6 char 2.2.1 class 4.11.2
compl 4.9.8; 4.9.3 const 3.2.1c const_cast 4.9.9a
continue 4.10.4 default 4.10.2 delete 4.9.21
do 4.10.3 double 2.2.1 dynamic_cast 4.9.9c
else 4.10.2 enum 3.2.3g, 4.7 explicit 4.11.2d1
export 4.12.1b extern 4.1.8d, 1.4.4 false 3.2.1b
float 2.2.1 for 4.10.3 friend 4.11.2a1
goto 4.10.4 if 4.10.2 inline 4.4.6b
int 2.2.1 long 2.2.3 mutable 4.1.8e
namespace 4.1.11 new 4.9.20 not 4.9.8
not_eq 4.9.8 operator 4.9.18 or 4.9.8
or_eq 4.9.8 private 4.11.2a protected 4.11.2a
public 4.11.2a register 4.1.8b reinterpret_cast 4.9.9d
return 4.4.7 short 2.2.3 signed 2.2.3
sizeof 4.9.13 static 4.1.8c static_cast 4.9.9b
struct 4.5 switch 4.10.2 template 4.12
this 4.11.6 throw 1.6 true 3.2.1b
try 1.6 typedef 3.2.1a typeid 4.9.14
typename 3.2.1e union 4.6 unsigned 2.2.3
using 4.1.11 virtual 4.11.2c1 void 2.2.1
volatile 3.2.1d; 4.1.9 wchar_t 2.2.1a1, 3.2.3d while 4.10.3

xor 4.9.8 xor_eq 4.9.8

En este apartado estudiaremos las palabras clave C++, que por una u otra razn no sean
introducidas en ningn otro epgrafe. Para distinguirlas del resto, a lo largo de esta obra, cuando
aparecen fuera del cdigo fuente, se imprimen en negrita y color negro. Por ejemplo, int es una
palabra clave...
Nota: las palabras clave __try y try son una excepcin. Dentro del mecanismo de manejo
de excepciones de C++ ( 1.6), la palabratry es necesaria como contraparte de catch. Por
otra parte, try no puede ser sustituida por __try. La palabra clave __try solo se utiliza
emparejada con __except o __finally.

3.2.1a typedef
1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo. No crea
ningn nuevo tipo, solo define un nuevo identificador (type-id 2.2) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresin compleja que contiene al
nombre). Es importante recalcar que el nuevo nombre es un aadido, y no sustituye al identificador
original. Ambos identificadores pueden ser intercambiados libremente en cualquier expresin.
Formalmente typedef es un especificador de identificador (nombre). Su introduccin en el lenguaje
se debe a que, como reconoce su propio creador [1], la sintaxis de declaraciones C++ es
innecesariamente dura de leer y escribir. Esto se debe a la herencia del C y a que la notacin no
es lineal, sino que mimetiza la sintaxis de las expresiones que est basada en precedencias. En
este sentido, la utilizacin de typedef permite paliar en parte el problema, mejora la legibilidad y
ayuda a la documentacin y mantenimiento del programa, ya que permite sustituir identificadores
de tipo complejos por expresiones ms sencillas.
2 Sintaxis:
typedef <tipo> <alias>;
Asigna un nombre <alias> con el tipo de dato de <tipo>.
Nota: para distinguir un identificador <alias> introducido con un typedef de un nombre de
tipo normal <tipo>, al primero se le denomina nombre-typedef ("typedef-name") o alias-
typedef ("typedef-alias").
Los typedef pueden ser usados con tipos simples o abstractos, pero no con nombres de
funciones.
3 Ejemplos:
typedef unsigned char BYTE;
en lo sucesivo, cualquier referencia a BYTE (es una tradicin de C/C++ utilizar los alias-typedef en
maysculas) equivale a colocar en su lugarunsigned char, incluso para crear nuevos
tipos unsigned char:
BYTE z, y // equivale a: unsigned char z, y
...
typedef const float KF;
typedef const float* KF_PTR;
KF pi = 3.14;
KF_PTR ppi = &pi;
typedef long clock_t; // no sera muy C++, mejor CLOCK_T
clock_t slice = clock();

3.1 En realidad el nuevo identificador introducido por typedef se comporta dentro de su mbito
como una nueva palabra-clave con la que pueden declararse nuevos tipos:
typedef int* Pint;
...
Pint p1, p2; // Ok. p1 y p2 son punteros-a-int
Tambin pueden encadenarse, de forma que pueden definirse nuevos alias en funcin de otros
definidos previamente. Por ejemplo:
typedef char CHAR;
typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;

3.2 Como en otras declaraciones, es posible definir una serie de alias-typedef mediante
expresiones unidas por comas. Por ejemplo:
typedef const char * LPCCH, * PCCH, * LPCSTR, * PCSTR ;
...
LPCCH ptr1 = "Hola Amrica";
PCSTR ptr2 = "Hola Amrica";
const char* ptr3 = "Hola Amrica";
Los punteros ptr1; ptr2 y ptr3 son equivalentes.
Otros ejemplos (tomados de definiciones reales de MS VC++)
typedef long INT_PTR, *PINT_PTR;
typedef unsigned short UHALF_PTR, *PUHALF_PTR;
typedef short HALF_PTR, *PHALF_PTR;

3.3 Otros ejemplos de typedef utilizados frecuentemente en la programacin Windows (
Ejemplos):
4 Asignaciones complejas
Es til utilizar typedef para asignaciones complejas; en particular en la declaracin y definicin de
punteros a funciones. Por ejemplo:
typedef long (*(*(*FPTR)())[5])(); // L.1
FPTR an; // L.2
La sentencia L.1 define un identificador: FPTR como un puntero a funcin que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcin, que no reciben ningn
parmetro y devuelven long. Despus, L.2 declara que an es un elemento del tipo indicado.
typedef void (new * new_handler)(); // L.3
new_handler set_new_handler(new_handler); // L.4
L:3 define new_handler como el identificador de un puntero a funcin que no recibe argumentos
y devuelve void [2]. Despus L.4 declaraset_new_handler como el nombre de una funcin que
devuelve el tipo new_handler recin definido y acepta un nico argumento de este mismo tipo.
typedef void (X::*PMF)(int); // L.5
PMF pf = &X::func; // L.6
L.5 define el identificador PMF como puntero a funcin-miembro de la clase X que recibe un int y
no devuelve nada. L.6 declara pf como tipo PMF(puntero a funcin...) que apunta al
mtodo func de X.

4.1 Cuando se trata de expresiones muy complejas, puede ser til proceder por fases,
aprovechando la propiedad ya enunciada (3.1 ) de que pueden definirse nuevos alias en
funcin de otros definidos previamente . Por ejemplo, queremos definir un puntero p a matriz de 5
punteros a funcin que toman un entero como argumento y devuelven un puntero a carcter. En
este caso, puede ser conveniente empezar por las funciones:
char* foo(int); // foo es una funcin aceptando int y
devolviendo char
typedef char* F(int); // F es un alias de funcin aceptando int y
devolviendo...
a continuacin definimos la matriz:
F* m[5]; // m es una matriz de 5 punteros a F
typedef F* M[5]; // M es el alias de una matriz de 5 punteros a F
Finalmente escribimos la declaracin del tipo solicitado:
M* p;
Cualquier manipulacin posterior del tipo mencionado resulta ahora mucho ms sencilla. Por
ejemplo, la declaracin:
int* foo(M*);
corresponde a una funcin aceptando un puntero a matriz... que devuelve un puntero a int.

4.2 En ocasiones, la simplificacin mencionada el en prrafo anterior, permite solventar algn
que otro problema con la compilacin de expresiones complejas. Por ejemplo, un miembro de
cierta clase tiene la siguiente declaracin:
class MYClass {
...
MyNAMESPACE::Garray<MyNAMESPACE::MyString> arrQuer;
...
}
Como sugiere su nombre, Garray es una clase genrica, destinada a almacenar matrices de
objetos de cualquier tipo, est definida en el espacio de nombres MyNAMESPACE. En este caso, el
objeto arrQuer es una matriz de objetos tipo MyString, que es una clase para manejar cadenas
de caracteres -similar a la conocida string de la librera estndar de plantillas STL- tambin
definida en MyNAMESPACE. En resumen, arrQuer es una matriz de cadenas de caracteres.
Ocurre que deseo incluir una invocacin explcita para la destruccin del objeto arrQuer en el
destructor de MYClass, Algo como:
class MYClass {
...
MyNAMESPACE::Garray<MyNAMESPACE::MyString> arrQuer;
...
~MYClass() {
arrQuer.~MyNAMESPACE::Garray<MyNAMESPACE::MyString>(); //
Compiler error
}
}
Sin embargo, el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sealada. En este caso, la utilizacin de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacin.
class MYClass {
...
typedef MyNAMESPACE::Garray<MyNAMESPACE::MyString> ZSTR;
ZSTR arrQuer;
...
~MYClass() {
arrQuer.~ZSTR(); // Compilacin Ok.
}
}

&5 Tambin es posible utilizar typedef al mismo tiempo que se declara una estructura u otro tipo
de clase. Ejemplo:
typedef {
double re, im;
} COMPLEX;
...
COMPLEX c, *ptrc, Arrc[10];

La anterior corresponde a la definicin de una estructura annima que puede ser utilizada a travs
de su typedef. Por supuesto, aunque no es usual necesitar el nombre y el alias simultneamente,
tambin se puede poner nombre a la estructura al mismo tiempo que se declara el typedef. Por
ejemplo:
typedef struct C1 {
double re, im;
} COMPLEX;
...
C1 c, *ptrc;
COMPLEX Arrc[10];
Otro ejemplo tomado de una definicin real: ( 4.5.5c)

&6 Otro uso de typedef puede consistir en localizar determinadas referencias concretas en un
solo punto (donde se declara el typedef), de forma que los posibles cambios posteriores solo
requieren cambiar una lnea de cdigo ( en mi opinin, quizs sea esta la razn ms
importante para la utilizacin de este especificador). Por ejemplo, supongamos que necesitamos
una variable de 32 bits y estamos utilizando C++Builder, en el queint tiene justamente 32 bits (
2.2.4); a pesar de ello utilizamos la expresin:
typedef int INT32;
en lo sucesivo, para todas las referencias utilizamos INT32 en vez de int. Por ejemplo:
INT32 x, y, z;
Si tuvisemos que portar el cdigo a una mquina o a un compilador en el que int fuese menor y,
por ejemplo, los 32 bits exigieran un long int, solo tendramos que cambiar la lnea de cdigo
del typedef:
typedef long INT32; // Todas las dems referencias se mantienen
...
INT32 x, y, z; // Ok.

7 No est permitido usar typedef con clases de declaracin adelantada ( 4.11.4). Por ejemplo
sera incorrecto:
typedef struct COMPLEX; // Ilegal!!
Tampoco est permitido utilizarlo en la definicin de funciones o utilizar dos veces el mismo
identificador en el mismo espacio de nombres:
typedef long INT32;
...
typedef float INT32; // Error!!

Cuando el alias-typedef se refiere a una clase, se constituye en un nombre de clase. Este alias no
puede ser utilizado despus de los prefijosclass, struct o union. Tampoco puede ser utilizado con
los nombres de constructores o destructores dentro de la clase. Ejemplo:
typedef struct S {
...
S(); // constructor
~S(); // destructor
} STR;
...
S o1 = STR(); // Ok.
STR o2 = STR(); // Ok.
struct STR* sp; // Error!!
Observe que:
typedef struct {
...
S(); // Error!!
~S(); // Error!!
} STR;
...
S() y ~S() seran tratadas como funciones normales, no como constructor y destructor de la
estructura.

8 Cuando se quiere utilizar un alias para el identificador de un espacio de nombres, el
mecanismo es distinto; no es necesario utilizar typedef. Ver: Alias de subespacios ( 4.1.11a).

Typedefs en Windows:
1 Sinopsis
Los typedef son de utilizacin muy comn, ya que en muchas ocasiones suponen una economa y
simplificacin en la notacin. Sin embargo, como hemos sealado ( 3.2.1a), una de las razones
de su uso, y quizs la ms importante, es que permite concentrar en un solo punto del cdigo
determinadas referencias, lo que resulta decisivo para la portabilidad de aplicaciones entre
distintas plataformas. Este es precisamente el caso de las aplicaciones escritas para la API de
Windows, donde se utilizan con profusin estos nombres alternativos. Su uso permite a los
desarrolladores despreocuparse de determinadas cuestiones de detalle, y utilizar los mismos
identificadores en sus aplicaciones, con independencia de que estas puedan ser posteriormente
compiladas para versiones Windows de 16, 32 o 64 bits. Por ejemplo, la aplicacin puede utilizar
un tipo UINT en todas las funciones que devuelven dicho tipo, con independencia de como sea
interpretado finalmente por el compilador. Este detalle ser encomendado a los ficheros de
cabecera, que pueden contener distintas definiciones de este typedef para cada compilador
concreto.
A continuacin se exponen algunos de los identificadores ms utilizados en la programacin C/C++
para Windows, junto con una breve descripcin de sus caractersticas.
WINAPI En realidad no se refiere a un tipo de dato, sino a una convencin de llamada a
funcin ( 4.4.6a). En las primitivas versiones de Windows, este identificador se
refera a la convencin _pascal. En las versiones de 32 bits se corresponde con la
convencin estndar de llamada. En particular, la funcin WinMain, que en estas
aplicaciones sustituye a la funcin main del C/C++ estndar, utiliza esta
convencin.
CALLBACK Es otra convencin de llamada. En particular para aquellas fuciones de retrollamada
("call-back") de la aplicacin, que deben ser invocadas por el Sistema Operativo. Es
el caso de los denominados "window procedures" y "dialog
procedures". Inicialmente se referan a la convencin FAR PASCAL, pero
actualmente son llamadas estndar (_stdcall). En concreto, el "window procedure"
responde al siguiente prototipo:

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
LPSTR Punteros a matrices de caracteres. Generalmente cadenas alfanumricas al estilo
C clsico, terminadas en el carcter nulo (NTBSs 3.2.3f). Definidas
como char FAR* [3]
LPCSTR Anlogos a los anteriores pero referidos a matrices de caracteres constantes (de
solo lectura). Definido como const char FAR*
UINT Un tipo de entero sin signo cuyo tamao depende del entorno (Windows 16, 32 o 64
bits). Es sinnimo de unsigned int, y generalmente es utilizado en sustitucin del
tipo WORD, excepto en las contadas ocasiones en que se desea un valor sin signo de
16 bits aunque se trate de plataformas de 32 o 64 bits.
LRESULT Este es el tipo devuelto por las funciones "call-back" (window procedure y dialog
procedure).
WPARAM
Las funciones call-back aceptan cuatro parmetros, dos de los cuales son de
propsito general. Este tipo corresponde a uno de ellos .
LPARAM Tipo del segundo parmetro de uso general de las funciones "call-back".
LPVOID
Puntero genrico, equivalente a void*. Suele utilizarse con preferencia a LPSTR.

En la mayora de los casos, el intercambio de datos entre las aplicaciones Window y la API
Sistema, se concreta en estructuras (en el sentido C del trmino) que se definen mediante los
oportunos "defines" y que se manejan a travs de punteros, que aqu son conocidos como
manejadores ("hanles"). Muchas funciones de la API, tanto de servicios generales como de
servicios grficos (GDI), reciben y devuelven estos "handles". Que a su vez se presentan mediante
distintos identificadores que finalmente son traducidos en la fase de preproceso a punteros-a-
estructuras de distinto tipo. A continuacin se relacionan algunos de los ms frecuentes.
HANDLE manejador genrico. Debe ser sustituido por uno ms especfico siempre que sea
posible.
HINSTANCE
handle a instancia de una aplicacin (por ejemplo, el programa en ejecucin).
HDC
handle a contexto grfico DC ("device context"). Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows
(objetos grficos); sus atributos y modos que afectan a sus salidas. Entre estos
objetos estn una pluma "pen" para trazado de lneas; un pincel "brush", para
relleno de reas; un mapa de bits "bitmap"; una paleta de colores; una referencia al
rea "canvas" en la que se realizarn las operaciones de dibujo, y una regin dentro
de ella.
HMODULE
handle a mdulo.
HBITMAP
handle a bitmap.
HLOCAL
handle a local.
HGLOBAL
handle a global.
HTASK
handle a tarea (proceso).
HFILE
handle a fichero.
HRSRC
handle a recurso.
HGDIOBJ
handle a objeto de la interfaz de diseo grfico GDI ("Graphic Design Interface").
Excepto metaficheros
HMETAFILE
handle a metafichero.
Nota: las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imgenes: los metaficheros ("metafiles") y los mapas de bits
("bitmaps"). Los metaficheros son matrices de estructuras de longitud variable
que, al contrario que los mapas de bits, almacenan la informacin grfica en un
formato independiente de cualquier dispositivo concreto (device-independent
format).
HDWP
handle a una estructura DeferWindowPos(). Esta funcin cambia la estructura que
define la posicin y tamao de una ventana.
HACCEL
handle a tabla de aceleradores. Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras ("accelerator's keystrokes") de un hilo
de ejecucin ("thread"). Responden a la siguiente definicin:

typedef struct tagACCEL {
BYTE fVirt;
WORD key;
WORD cmd;
} ACCEL;
HDRVR
handle a controlador de dispositivo ("driver").
HWND
handle a caja una ventana. Por ejemplo una caja de dilogo ("dialog box"); un
botn; etc.

A continuacin se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1]. Como puede comprobar, algunos estn definidos en funcin de otros en un
proceso recursivo, aunque el preprocesador las traslada finalmente a su definicin definitiva. Por
ejemplo, WPARAM es UINT que finalmente es considerado por el compilador equivalente unsigned
int [2].
typedef char CHAR, CCHAR, *PCCHAR;;
typedef unsigned char BYTE, UCHAR, *PUCHAR;
typedef unsigned short WORD, USHORT, ATOM, *PUSHORT;
typedef short SHORT, *PSHORT;
typedef unsigned int UINT, WPARAM;

typedef int INT, HFILE;
typedef HICON HCURSOR;

typedef double DOUBLE;
typedef unsigned long DWORD, ULONG, *PULONG;
typedef long BOOL, LONG, LPARAM, LRESULT, *PLONG;
typedef float FLOAT, *PFLOAT;
typedef unsigned char UCHAR,*PUCHAR;
typedef wchar_t WCHAR, TCHAR, OLECHAR;
typedef char *PSZ;
typedef unsigned int * PUINT;

typedef TCHAR TBYTE,*PTCH,*PTBYTE;
typedef TCHAR *LPTCH,*PTSTR,*LPTSTR,*LP,*PTCHAR;
typedef const TCHAR *LPCTSTR;
typedef void *HANDLE;
typedef PVOID HANDLE;

typedef HANDLE HDWP, *PHANDLE,*LPHANDLE;
typedef DWORD COLORREF; // Valores de color RGB Windows
typedef hyper LONGLONG;
typedef DWORD * LPCOLORREF;
typedef CHAR *PCHAR, *LPCH, *PCH, *NPSTR, *LPSTR, *PSTR;
typedef const CHAR *LPCCH, *PCCH, *LPCSTR, *PCSTR ;
typedef WCHAR *PWCHAR, *LPWCH, *PWCH, *NWPSTR, *LPWSTR, *PWSTR;
typedef const WCHAR *LPCWCH, *PCWCH, *LPCWSTR, *PCWSTR, *LPCCH, *PCCH;
typedef VOID void
typedef void *PVOID,*LPVOID;
3.2.1b bool, false, true
1 Sinopsis
La palabra-clave bool declara un tipo especial de variable, denominada booleana ( 0.1) que
solo puede tener dos valores: cierto y falso [1].
Nota: por razn de los valores que pueden adoptar (cierto/falso), a estas variables tambin se
las denomina variables lgicas.
2 Sintaxis
bool <identificador>;
3 Descripcin
Evidentemente el tipo bool est especialmente adaptado a para realizar comprobaciones lgicas;
de hecho, todo el lgebra de Boole se basa justamente en el uso de este tipo de variables de solo
dos valores mutuamente excluyentes.
Por su parte, las palabras clave false y true son literales que tienen valores predefinidos
(podemos considerar que son objetos de tipo booleano de valor constante predefinido). false tiene
el valor falso (numricamente es cero), true tiene el valor cierto (numricamente es uno). Estos
literales booleanos son Rvalues; no se les puede hacer una asignacin (no pueden estar a la
izquierda de una asignacin 2.1).
bool val = false; // declara val variable Booleana y la inicia
val = true; // ahora se cambia su valor (nueva asignacin)
true = 0; // Error!!
4 Conversin (modelado) de tipos:
Tenga en cuenta que los bool y los int son tipos distintos. Sin embargo, cuando es necesario, el
compilador realiza una conversin o modelado automtico ( ), de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado explcito. Por
ejemplo:
int x = 0, y = 5;
if (x == false) printf("x falso.\n"); // Ok.
if (y == truee) printf("y cierto.\n"); // Ok.
if ((bool) x == false) printf("x falso.\n"); // Modelado innecesario
Estas conversiones entre tipos lgicos y numricos, son simplemente una concesin del C++
para poder aprovechar la gran cantidad de cdigo C existente. Tradicionalmente en C se haca
corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero).
El proceso consiste en que, en las expresiones aritmticas y lgicas, las variables booleanas son
convertidas a enteros (int). Las operaciones correspondientes (aritmticas y lgicas) se realizan
con enteros, y finalmente el resultado numrico es vuelto a bool segn las reglas de conversin
siguientes:
Para convertir tipos bool a tipos int: false cero
true uno
Para convertir tipos int a un Rvalue tipo bool: cero false
cualquier otro valor true.

Para el resto de variables distintas de int (aunque sean numricas), antes de utilizarlas en
expresiones lgicas ( 4.9.9), es necesario un modelado ("casting"). Ejemplo:
float x = 0
long y = 5;
int *iptr = 0;
if (x == false) printf("x falso"); // Error.
if (y == truee) printf("y cierto"); // Error.
if (iptr == false) printf("Puntero nulo"); // Error.
if ((bool) x == false) printf("x falso"); // Ok.
if ((bool) y == true) printf("y cierto"); // Ok.
if ((bool) iptr == false) printf("Puntero nulo"); // Ok.
Las reglas son anlogas a las anteriores:
Para convertir un Rvalue tipo bool a un Rvalue numrico: false cero
true uno.
Para convertir tipos aritmticos (enumeraciones, punteros o punteros a miembros de
clases) a un Rvalue de tipo bool, la regla es que cualquier valor cero; puntero nulo, o
puntero a miembro de clase nulo, se convierte a false. Cualquier otro valor se convierte
a true.

5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
lgicas. En el ejemplo que sigue se muestra como hacer test booleanos con bool, true, y false:
#include <iostream>
using std::cout;
using std::endl;

bool func() { // Func devuelve un tipo bool
return NULL; /* NULL es convertido a Booleano (false)
return false; esta sentencia es idntica a la anterior */
}

int main() { // ==============
bool val = false; // val es declarada tipo bool e iniciada
int i = 1; // i es tipo int (no booleano)
int *iptr = 0; // puntero nulo, equivale a: int *iptr = NULL
float j = 1.01; // j es tipo float (no booleano)

// Test para enteros
if (i == true) cout << "Cierto: el valor es 1" << endl;
if (i == false) cout << "Falso: el valor es 0" << endl;

// Test para punteros
if ((bool) iptr == false) cout << "Puntero no vlido" << endl;
// Para comprobar el valor j se "modela" a tipo bool.
if ((bool) j == true) cout << "el Booleano j es cierto" << endl;
// Test de funcin devolviendo Booleano
val = func();
if (val == false)
cout << "func() devuelve falso.";
if (val == true)
cout << "func() devuelve cierto.";
return false; // false es convertido a 0 (int)
}
Salida del programa:
Cierto: el valor es 1
Puntero no vlido
el Booleano j es cierto
func() devuelve falso

6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool, son las siguientes:
Operadores lgicos ( 4.9.8) AND (&&) OR (||) NOT (!). Producen un
resultado booleano, y sus operandos son tambin valores lgicos o asimilables a ellos (los
valores numricos son asimilados a true o false segn su valor).
Operadores relacionales ( 4.9.12) <, >, <=, >=. Aceptan diversos tipos de operando,
pero el resultado es de tipo booleano.
Expresin condicional en las sentencias if ( 4.10.2) y en las
iteraciones for, while y do..while ( 4.10.3). En todos estos casos, la sentencia
condicional produce un bool como resultado.
El primer operando del operador ? : ( 4.9.6), es convertido a bool.

3.2.1b bool, false, true
1 Sinopsis
La palabra-clave bool declara un tipo especial de variable, denominada booleana ( 0.1) que
solo puede tener dos valores: cierto y falso [1].
Nota: por razn de los valores que pueden adoptar (cierto/falso), a estas variables tambin se
las denomina variables lgicas.
2 Sintaxis
bool <identificador>;
3 Descripcin
Evidentemente el tipo bool est especialmente adaptado a para realizar comprobaciones lgicas;
de hecho, todo el lgebra de Boole se basa justamente en el uso de este tipo de variables de solo
dos valores mutuamente excluyentes.
Por su parte, las palabras clave false y true son literales que tienen valores predefinidos
(podemos considerar que son objetos de tipo booleano de valor constante predefinido). false tiene
el valor falso (numricamente es cero), true tiene el valor cierto (numricamente es uno). Estos
literales booleanos son Rvalues; no se les puede hacer una asignacin (no pueden estar a la
izquierda de una asignacin 2.1).
bool val = false; // declara val variable Booleana y la inicia
val = true; // ahora se cambia su valor (nueva asignacin)
true = 0; // Error!!
4 Conversin (modelado) de tipos:
Tenga en cuenta que los bool y los int son tipos distintos. Sin embargo, cuando es necesario, el
compilador realiza una conversin o modelado automtico ( ), de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado explcito. Por
ejemplo:
int x = 0, y = 5;
if (x == false) printf("x falso.\n"); // Ok.
if (y == truee) printf("y cierto.\n"); // Ok.
if ((bool) x == false) printf("x falso.\n"); // Modelado innecesario
Estas conversiones entre tipos lgicos y numricos, son simplemente una concesin del C++
para poder aprovechar la gran cantidad de cdigo C existente. Tradicionalmente en C se haca
corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero).
El proceso consiste en que, en las expresiones aritmticas y lgicas, las variables booleanas son
convertidas a enteros (int). Las operaciones correspondientes (aritmticas y lgicas) se realizan
con enteros, y finalmente el resultado numrico es vuelto a bool segn las reglas de conversin
siguientes:
Para convertir tipos bool a tipos int: false cero
true uno
Para convertir tipos int a un Rvalue tipo bool: cero false
cualquier otro valor true.

Para el resto de variables distintas de int (aunque sean numricas), antes de utilizarlas en
expresiones lgicas ( 4.9.9), es necesario un modelado ("casting"). Ejemplo:
float x = 0
long y = 5;
int *iptr = 0;
if (x == false) printf("x falso"); // Error.
if (y == truee) printf("y cierto"); // Error.
if (iptr == false) printf("Puntero nulo"); // Error.
if ((bool) x == false) printf("x falso"); // Ok.
if ((bool) y == true) printf("y cierto"); // Ok.
if ((bool) iptr == false) printf("Puntero nulo"); // Ok.
Las reglas son anlogas a las anteriores:
Para convertir un Rvalue tipo bool a un Rvalue numrico: false cero
true uno.
Para convertir tipos aritmticos (enumeraciones, punteros o punteros a miembros de
clases) a un Rvalue de tipo bool, la regla es que cualquier valor cero; puntero nulo, o
puntero a miembro de clase nulo, se convierte a false. Cualquier otro valor se convierte
a true.

5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
lgicas. En el ejemplo que sigue se muestra como hacer test booleanos con bool, true, y false:
#include <iostream>
using std::cout;
using std::endl;

bool func() { // Func devuelve un tipo bool
return NULL; /* NULL es convertido a Booleano (false)
return false; esta sentencia es idntica a la anterior */
}

int main() { // ==============
bool val = false; // val es declarada tipo bool e iniciada
int i = 1; // i es tipo int (no booleano)
int *iptr = 0; // puntero nulo, equivale a: int *iptr = NULL
float j = 1.01; // j es tipo float (no booleano)

// Test para enteros
if (i == true) cout << "Cierto: el valor es 1" << endl;
if (i == false) cout << "Falso: el valor es 0" << endl;

// Test para punteros
if ((bool) iptr == false) cout << "Puntero no vlido" << endl;
// Para comprobar el valor j se "modela" a tipo bool.
if ((bool) j == true) cout << "el Booleano j es cierto" << endl;
// Test de funcin devolviendo Booleano
val = func();
if (val == false)
cout << "func() devuelve falso.";
if (val == true)
cout << "func() devuelve cierto.";
return false; // false es convertido a 0 (int)
}
Salida del programa:
Cierto: el valor es 1
Puntero no vlido
el Booleano j es cierto
func() devuelve falso

6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool, son las siguientes:
Operadores lgicos ( 4.9.8) AND (&&) OR (||) NOT (!). Producen un
resultado booleano, y sus operandos son tambin valores lgicos o asimilables a ellos (los
valores numricos son asimilados a true o false segn su valor).
Operadores relacionales ( 4.9.12) <, >, <=, >=. Aceptan diversos tipos de operando,
pero el resultado es de tipo booleano.
Expresin condicional en las sentencias if ( 4.10.2) y en las
iteraciones for, while y do..while ( 4.10.3). En todos estos casos, la sentencia
condicional produce un bool como resultado.
El primer operando del operador ? : ( 4.9.6), es convertido a bool.


3.2.1c const
1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato, sealado por un identificador, no
pueda ser modificado a lo largo del programa (sea constante). El especificador const se puede
aplicar a cualquier objeto de cualquier tipo, dando lugar a un nuevo tipo con idnticas propiedades
que el original pero que no puede ser cambiado despus de su inicializacin (se trata pues de un
verdadero especificador de tipo).
Cuando se utiliza en la definicin de parmetros de funciones o con miembros de clases ,
tiene significados adicionales especiales.
2 Sintaxis
Existen cuatro formas posibles:
const [<tipo-de-variable>] <nombre-de-variable> [ = <valor> ]; 2.1
<nombre-de-funcin> ( const <tipo>*<nombre-de-variable> ); 2.2
<nombre-de-metodo> const; 2.3
const <instanciado de clase>; 2.4
Nota: observe que no consideramos aqu la forma:

const [<tipo-de-variable>] <nombre-de-funcin> (...);
Significara una funcin devolviendo un tipo constante.
Como el lector puede suponer, la pluralidad de formas sintcticas permitidas trasluce la variedad
de significados que, dependiendo de las circunstancias, puede asumir esta palabra clave. Esta
variedad se traduce en un comportamiento camalenico que cuesta trabajo asimilar en toda su
extensin. Mxime si se le suma el hecho de que su comportamiento puede ser afectado por
ciertos especificadores adicionales.
3 Descripcin
La palabra clave const declara que un valor no es modificable por el programa. Puesto que no
puede hacerse ninguna asignacin posterior a un identificador especificado como const, esta debe
hacerse inevitablemente en el momento de la declaracin, a menos que se trate de una
declaracin extern ( 4.1.8d).
Ejemplos:
const float pi = 3.14; // una constante float
char *const pt1 = "Sol"; // pt1 puntero constante-a-char
char const *pt2 = "Luna"; // pt2 puntero-a-cadena-de-char constante
const char *pt2 = "Luna"; // idem.
const peso = 45; // una constante int
const float talla; // Error!! no inicializada
extern const int x // Ok. declarada extern

4 Es importante insistir en el concepto de que tipoX-const y tipoX son tipos distintos (no se trata
solamente de que a dicha variable no se le pueda cambiar el valor). Esto tiene importantes
repercusiones prcticas; como veremos ( 4.2.1a), un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX.

5 Cuando no se indica <tipo-de-variable>, en ausencia de otro especificador, const por s
misma equivale a int.
const *ptr ; // Puntero a int constante
cons x = 10; // Entero constante

6 Un carcter entre comillas simples es un carcter constante const char (declaracin implcita),
y puede ser asignado a una variable, o utilizado en cualquier lugar que un char normal:
const char letra_a = 'a';

7 Cualquier futuro intento de asignacin a una constante origina un error de compilacin (aunque
el resultado exacto depende de la implementacin), por lo que segn las declaraciones
anteriores , las que siguen son ilegales.
pi = 3.0; // NO! Asigna un valor a una constante.
i = peso++; // NO! Incrementa una constante.
pt1 = "Marte" // NO! Apunta pt1 a otra entidad
8 const y volatile
Aunque en principio pueda parecer un contrasentido, el especificador const puede coexistir con el
atributo volatile ( 3.2.1d). Por tanto es vlida la expresin:
const volatile int x = 33;
Para el compilador viene a significar que la variable x no puede aceptar modificaciones a lo largo
del programa, pero que su valor inicial 33, puede variar por causas externas, por lo que no se
pueden hacer suposiciones sobre su valor actual.
9 const con punteros
Puesto que el especificador const crea un nuevo tipo, un puntero a-tipoX es considerado distinto
de un puntero a-constante-tipoX. Considere el siguiente ejemplo:
int x = 10;
int* xptr = &x; // Ok.
cons int y = 10;
int* yptr = &y; // L.4: Error:
const int* yptr = &y; // Ok.

Observe que const-tipoX* no puede ser asignado a tipoX*, que es el error que se produce en L.4.
En este caso, el compilador lo expresa: "Cannot convert 'const int *' to 'int *'
..."; sin embargo, la inversa s es posible, es decir: tipoX* puede ser asignado a const-tipoX*:
int y = 10;
const int* yptr = &y; // Ok. !!

Tenga en cuenta que un puntero declarado como constante no puede ser modificado, pero el
objeto al que seala s que puede modificarse (de hecho, el objeto sealado no tiene porqu ser
constante). Siguiendo con las definiciones anteriores, puede hacerse:
char *const pt1 = "Sol"; // pt1 puntero constante-a-char
char *pt3 = pt1; // el puntero pt3 seala a la cadena "Sol"
pt3++; // el puntero pt3 seala a la cadena "ol"
*pt3 = 'a'; // modifica segundo carcter de "Sol"
cout << pt1; // -> "Sal"
Nota: en determinados casos, una constante puede ser indirectamente modificada a travs de
un puntero, aunque no sea aconsejable y el resultado dependa de la implementacin. Ver una
discusin mas detallada sobre este asunto de punteros y constantes: Puntero constante/a
constante ( 4.2.1e).

10 El atributo const puede ser reversible. C++ dispone de un operador especfico que puede
poner o quitar este atributo de un objeto ( 4.9.9aoperador const_cast); se trata de una especie
de "casting" especfico de la propiedad const, aunque con ciertas limitaciones.

11 const en parmetros de funciones
El especificador const puede ser utilizado en la definicin de parmetros de funciones. Esto
resulta de especial utilidad en tres casos; en los tres el fin que se persigue es el mismo: indicar que
la funcin no podr cambiar dichos argumentos (segundo caso de la sintaxis ):
Con parmetros de funciones que sean de tipo matriz (que se pasan por
referencia). Ejemplo:
int strlen(const char[]);
Cuando los parmetros son punteros (a fin de que desde dentro de la funcin no puedan
ser modificados los objetos referenciados). Ejemplo:
int printf (const char *format, ...);
Cuando el argumento de la funcin sea una referencia, previniendo as que la funcin
pueda modificar el valor referenciado. Ejemplo:
int dimen(const X &x2);
En los tres casos sealados, la declaracin de los parmetros como const, garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos.
12 const con miembros de clases
El declarador const puede utilizarse con clases de tres formas distintas:
Utilizado en el sentido tradicional (objeto-dato que no puede ser modificado) 12.1
Aplicado a mtodos de clase (con un sentido muy especial) 12.2
Aplicado a objetos (instancias de clase) asignndoles ciertas caractersticas 12.3

12.1 En el sentido tradicional del especificador
Cuando se aplica a propiedades de clase, indicando que se trata de constantes cuyo valor no
puede ser modificado a lo largo de la vida del programa. Ejemplo:
class C {
const int k; // declara k constante (private)
int x; // declara x no constante (private)
public:
int f1(C c1, const C& c2) { // declara argumento c2 constante
// (segundo caso de sintaxis)
c1.x = 3; // Ok: objeto c1 modificable
c1.k = 4; // Error: Miembro k no modificable
c2.x = 5; // Error: objeto c2 NO modificable
return (x + k + c1.x + c2.k);
}
...
};
Nota: puesto que en el cuerpo de la clase no pueden hacerse asignaciones, C++ proporciona
un mtodo especial para inicializar estas constantes (caso de k) ( 4.11.2d3).
12.2 Aplicado a mtodos de clase
Tercer caso de la sintaxis :
<nombre-de-funcin> const;
Si se utiliza el especificador const en la declaracin de un mtodo de clase, la funcin no puede
modificar ninguna propiedad en la clase. Este uso del especificador no puede utilizarse con
funcinoes normales, solo con funciones-miembro de clase.
Ejemplo
class C {
int x; // Private por defecto
int func(int i) const { // tercer caso de sintaxis
x = x + i; // Error: !
}
...
};
Al compilar este cdigo se produce un error: Cannot modify a const object in function
C::func(int) const, avisndonos que la funcin func declarada constante no puede
modificar el valor de la variable x (ni ningn otro miembro de C, sea o no constante).
Ntese que si la definicin de la funcin est fuera de la definicin de la clase, tambin es
necesario el especificador. En el ejemplo anterior:
class C {
int x;
int func(int) const;
...
};
...
inline int C::func(int i) const { /* ... */ }
Tenga en cuenta que en estos casos, el especificador const forma parte del tipo de la funcin
miembro, de forma que:
class C {
int x;
int func(int);
...
};
...
inline int C::func(int i) const { /* ... */ }
Produce un error de compilacin: 'C::func(int) const' is not a member of 'C'
Observe que el especificador const puede aparecer simultneamente en tres posiciones distintas
de la declaracin de un mtodo:
struct C {
int x;
const int& foo (const int&) const;
};
const int& C::foo(const int& i) const {
cout << "xxx " << x * i << endl;
return this->x;
}
...
void func() {
C c1 = {3};
int x = 3;
foo(x); // -> xxx 30
}
El primero significa que el valor devuelto por la funcin no podr ser utilizado para modificar el
objeto original. El segundo indica que el argumento recibido por la funcin no podr ser modificado
en el cuerpo de esta. El tercero seala que el mtodo C::foo no podr ser utilizado para modificar
ningn miembro de la estructura C a la que pertenece.
12.3 Aplicado a instancias de clases
Adems del sentido estricto de constante, cuando se utiliza con miembros de clases, const es una
caracterstica aadida de seguridad [2]. En efecto: los objetos definidos como const intentan usar
las funciones-miembro definidas a su vez como const .
En general estos objetos solo puede usar miembros que tambin estn definidos como const, de
forma que si un objeto-const invoca un mtodo no-const, el compilador muestra un mensaje de
alerta, avisando que un objeto-const est utilizando un miembro no-const.
Ejemplo
#include <iostream.h>

class C {
int num; // privado por defecto
public:
C(int i = 0) { num = i; } // constructor por defecto
int func(int i) const { // func declarada const
// tercer caso de la sintaxis
cout << "Funcion no-modificativa." << endl;
return i++;
}
int func(int i) { // versin no-const de func
cout << "Modifica datos privados" << endl;
return num = i; // modifica miembro num
}
int f(int i) { // funcin no-const
cout << "Funcion no-modificativa llamada con " << i << endl;
return i;
}
};

int main() { // ======================================
C c_nc; // Instancia-1 Utilizar miembros no-const
const C c_c; // Instancia-2 Utilizar miembros const
// cuarto caso de la sintaxis
c_nc.func(1); // invoca versin no-const de func
c_nc.f(1); // Ok. f es funcin no-const
c_c.func(1); // invoca versin cons de func
c_c.f(1); // Aviso: objeto-const invoca funcin no-const
}
Salida:
Modifica datos privados
Funcion no-modificativa llamada con 1
Funcion no-modificativa.
Funcion no-modificativa llamada con 1

Observe que la clase C tiene dos versiones de la misma funcin func. No se trata de un caso de
polimorfismo, puesto que ambas tienen exactamente la misma definicin. En ausencia del
especificador const en una de ellas, el compilador hubiese dado un error: Multiple
declaration for 'C::func(int)', pero la presencia de este modificador hace que el
compilador considere que ambos mtodos son distintos. La distincin de cual de las dos se
utilizar en cada invocacin de un objeto depende de que el propio objeto sea declarado const o
no-const.
En el ejemplo se han creado dos instancias de la clase: Una normal, no-const c_nc, y
otra const, c_c. Vemos que la invocacinc_nc.func(1); utiliza la versin no-const, mientras
que la invocacin c_c.func(1); utiliza la versin constante.
Puede comprobarse tambin que el compilador genera un mensaje de aviso en la penltima
lnea: Non-const function C::f(int) called for const object in function
main(), avisando que una funcin no-constante (f) ha sido invocada por un objeto constante
(c_c).
Nota: hay forma de saltarse esta restriccin: ver mutable ( 4.1.8e).
Temas relacionados:
Constantes ( 3.2.3): Todo lo referente a los diversos tipos de constantes y su
declaracin.
Cosntantes literales ( 3.2.3f): Un tipo especial de matrices de caracteres.
Enumeradores ( 3.2.3g): Un tipo especial de variable cuyo rango es una serie de
constantes enteras.
3.2.1d volatile
1 Sinopsis
Hemos sealado repetidas veces que una de las premisas de diseo del C++ es la velocidad de
ejecucin. En este sentido, los diseadores de estos compiladores adoptan todas las estrategias
posibles para garantizarlo. Por ejemplo, consideremos el siguiente trozo de cdigo:
...
func (/* ... */); // realiza determinado proceso
int limit = 1200; // definicin del lmite para el bucle
for (int c=0; c<limit; c++) func(/* ... */);
...

El proceso definido por func se repite mientras que el contador c se mantiene inferior al
lmite limit definido en la sentencia anterior. Puesto que en la condicin del for ( 4.10.3) no se
altera el valor de la variable limit, el compilador puede asumir que este valor se mantiene
constante durante la ejecucin del bucle, y puede que sea almacenado como variable de registro (
4.1.8b) a fin de ahorrarse lecturas y tenerla rpidamente accesible para la
comparacin c<limit, es ms que posible que c tambin sea declarada variable de registro, en
cuyo caso las operaciones de incremento unitario c++, y comparacin con limit, seran procesos
muy rpidos.
El problema es que, en determinadas circunstancias, este tipo de asunciones no es conveniente.
Por ejemplo, supongamos que el programa C++ al que corresponden las sentencias anteriores
est controlando un sistema de instrumentacin en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucin del programa - 1.7-).
En tales casos nos encontramos en una situacin justamente opuesta a las constantes (
3.2.1c). En aquel caso se indica al compilador: "Este valor se mantendr inalterable a lo largo
de la ejecucin". En ocasiones como la descrita, necesitamos indicar al compilador justamente lo
contrario: "No hacer ninguna suposicin sobre este valor, incluso si se ha ledo en la sentencia
anterior".
Para conseguir esto, C++ dispone de un indicador especfico; la palabra clave volatile es un
modificador que aadido a una variable, advierte al compilador que esta puede ser modificada por
una rutina en segundo plano (background), por una rutina de interrupcin, o por un dispositivo de
entrada salida. Es decir, que puede sufrir modificaciones fuera del control del programa.
La declaracin de un objeto con este atributo, previene al compilador de hacer ninguna asuncin
sobre el valor del objeto mientras se ejecutan instrucciones en las que est involucrado,
advirtindolo que dicho valor puede cambiar en cualquier momento. Tambin previene al
compilador de que no debe hacer de dicho objeto una variable de registro.
2 Sintaxis
volatile [<tipo-de-variable>] <nombre-de-variable> [ = <valor> ];
<nombre-de-funcin> ( volatile <tipo> <nombre-de-variable> );
<nombre-de-metodo> volatile;
volatile <instanciado de clase>;
3 Ejemplo
volatile int ticks; // primer caso de la sintaxis.
void timer( ) { ticks++; }
void wait (int interval) {
ticks = 0;
while (ticks < interval); // No hacer nada (esperar)
}
En este ejemplo, las rutinas implementan una espera de ciclos (ticks) especificados por el
argumento interval (asumiendo que el reloj est asociado a un dispositivo hardware de
interrupciones). Un compilador correctamente optimizado no debera cargar la
variable ticks dentro de la rutina de comprobacin del bucle while, dado que el bucle no cambia
el valor de dicha variable.
Otros ejemplos: 4.9.3; 9.1;
4 volatile y const
Como se ha sealado, el especificador const puede coexistir con el atributo volatile ( 3.2.1c)
5 volatile con punteros
Hay que hacer la salvedad de que, contra lo que ocurre con el especificador const, que crea un
nuevo tipo, el atributo volatile solo realiza determinadas advertencias al compilador, manteniendo
inalterado el tipo de variable sobre la que se aplica. Sin embargo, un puntero a-volatile-tipoX es
considerado diferente de un puntero a-tipoX normal, del mismo modo que puntero a-tipoX es
considerado distinto de puntero a-constante-tipoX.
Considere el siguiente ejemplo:
cons int x = 10;
int* xptr = &x; // Error:
const int* xptr = &x; // Ok.

volatile int y = 10;
int* yptr = &y; // Error:
volatile int* yptr = &y; // Ok.

int z;
volatile int* zptr = &z // Error:
6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y mtodos), de forma
parecida al modificador const con miembros de clase ( 3.2.1c). En efecto, puede ser utilizado de
tres formas distintas:

6.1 En el sentido tradicional del especificador.
Cuando se aplica a propiedades de clase, indicando que se trata de variables cuyo valor puede ser
modificado desde fuera del programa. En el ejemplo que sigue podemos encontrar la primera y
segunda formas de sintaxis:
class C {
volatile int x; // declara x volatile (private).
int f1(int x, volatile int y) { // declara argumento y volatile
return x + y + C::x;
}
...
};

6.2 Cuando se aplica a mtodos de clase (tercer caso de la sintaxis). Ejemplo:
<nombre-de-metodo> volatile;
Si en la declaracin de un mtodo de clase se utiliza volatile, la funcin debe ser invocada por
objetos tambin volatile (ver el siguiente caso). Este uso del atributo solo puede utilizarse con
funciones-miembro de clase.
Ejemplo:
class C {
int x; // Private por defecto
int func(int i) volatile { // declara func volatile
x = x + i;
}
...
};

6.3 Cuando se aplica a instancias de clase.
Adems del sentido estricto (variable que puede ser modificada desde fuera del programa), cuando
se utiliza con miembros de clases, volatile es una caracterstica aadida de seguridad. En efecto,
los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile. Si un
objeto volatile invoca una funcin miembro no-volatile, el compilador muestra un mensaje
avisando de la circunstancia.
Ejemplo:
#include <iostream.h>

class C {
int num; // privado por defecto
public:
C(int i = 0) { num = i; } // constructor por defecto
int func(int i) volatile { // version volatile de func
cout << "Funcion volatile" << endl;
return num = i; // modifica miembro no-volatile
}
int func(int i) { // versin no-volatile de func
cout << "Funcion no-volatile" << endl;
return num = i; // modifica miembro no-volatile
}
void f(int i) { // funcin no-volatile
cout << "Funcion no-volatile llamada con " << i << endl;
}
};

int main() { // =================================
C c_nv; // Instancia-1 Utilizar funciones no-
volatiles
volatile C c_v; // Instancia-2 Utilizar funciones
volatiles
// cuarto caso de la sintaxis
c_nv.func(1); // invoca versin no-volatil de func
c_nv.f(1); // Ok. f es funcin no-volatil
c_v.func(1); // invoca versin volatil de func
c_v.f(2); // Aviso: objeto-volatil invoca funcin no-
volatil
}
Salida:
Funcion no-volatile
Funcion no-volatile llamada con 1
Funcion volatile
Funcion no-volatile llamada con 2

Observe que la clase C tiene dos versiones de la misma funcin func, y que no se trata de un
caso de polimorfismo, puesto que ambas tienen exactamente la misma definicin. En ausencia del
especificador volatile en una de ellas, el compilador hubiese dado un error: Multiple
declaration for 'C::func(int)', pero la presencia de este modificador hace que el
compilador considere que ambos mtodos son distintos. La distincin de cual de las dos se
utilizar en cada invocacin de un objeto depende de que el propio objeto sea declarado volatile o
no-volatile.
En el ejemplo se han creado dos instancias de la clase: Una normal, no-volatile c_nv, y
otra volatile, c_v. Vemos que la invocacinc_nv.func(1); utiliza la versin no-volatile,
mientras que la invocacin c_v.func(1); utiliza la versin volatile.
Tambin puede comprobarse que el compilador genera un mensaje de aviso en la penltima
lnea: Non-volatile function C::f(int) called for volatile object in
function main(), avisando que una funcin no-voltil (f) ha sido invocada por un objeto voltil
(c_v).

7 El atributo volatile puede ser reversible. C++ dispone de un operador especfico que puede
poner o quitar este atributo de un objeto ( 4.9.9aoperador const_cast).

3.2.1e typename
1 Sinopsis
La palabra clave typename es un especificador de tipo. Indica justamente eso, que el identificador
que la acompaa es un tipo (aunque no se haya definido todava). Una especie de declaracin
adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal.
2 Sintaxis
Son posibles dos formas:
typename identificador 2a
template < typename identificador > identificador-de-clase 2b
3 Comentario
La forma 2a se utiliza para declarar variables que no han sido definidas todava. De esta forma se
evita que el compilador genere un error avisando que es un "tipo no definido". En el siguiente
ejemplo se utiliza esta sintaxis para utilizar miembros A de una clase T ( T::A ) que no ha sido
definida todava:
template <class T> // clase T no definida an

void f() {
typedef typename T::A TA; // L.3 declara TA como tipo T::A
TA a1; // L.4 declara a1 como de tipo TA
typename T::A a2; // declara a2 como de tipo T::A
TA * ptra; // declara ptra como puntero-a-TA
}
L.3 especifica que cada ocurrencia de TA ser sustituida por typename T::A, lo que significa que
por ejemplo, la sentencia L.4 es vista por el compilador como: typename T::A a1;.
La sintaxis 2b se utiliza en sustitucin de la palabra clave class en las declaraciones de plantillas
( 4.12.2). El sentido es el mismo; significa "este argumento es cualquier tipo". En el siguiente
ejemplo se utiliza esta sintaxis en la declaracin de dos funciones genricas:
template <typename T1, typename T2> T2 convert (T1 t1) { // L.1
return (T2)t1;
}
template <typename X, class Y> bool isequal (X x, Y y) { // L.5
if (x==y)return 1; return 0;
}

Observe que la definicin L.1 utiliza typename en sustitucin del especificador class, mientras
que en L.5 se utilizan indistintamente.
3.2.2 Identificadores
1 Sinopsis
Recordemos ( 1.2.1) que un identificador es un conjunto de caracteres alfanumricos de
cualquier longitud que sirve para identificar las entidades del programa (clases, funciones,
variables, tipos compuestos, Etc.) Los identificadores pueden ser combinaciones de letras y
nmeros. Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos. En
el caso de C++, son las que se indican a continuacin. Cuando un identificador se asocia a una
entidad concreta, entonces es el "nombre" de dicha entidad, y en adelante la representa en el
programa. Por supuesto puede ocurrir que varios identificadores se refieran a una misma entidad.
Nota: el concepto de "entidad" es muy amplio; corresponde a: un valor; clase; elemento de
una matriz; variable; funcin; miembro de clase; instancia de clase; enumerador; plantilla, o
espacio de nombres del programa.
2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z, el guin bajo "_"
("Underscore") y los dgitos 0 a 9.
Caracteres permitidos:
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
_
Dgitos permitidos
0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicin:
El primer carcter debe ser una letra o el guin bajo. El Estndar establece que los
identificadores comenzando con guin bajo y mayscula no deben ser utilizados. Este tipo
de nombres se reserva para los compiladores y las Libreras Estndar. Tampoco se
permite la utilizacin de nombres que contengan dos guiones bajos seguidos.
El estndar ANSI establece que como mnimo sern significativos los 31 primeros
caracteres, aunque pueden ser ms, segn la implementacin [1]. Es decir, para que un
compilador se adhiera al estndar ANSI, debe considerar como significativos, al menos, los
31 primeros caracteres.
Nota: veremos que los identificadores de los operadores ( 4.9) son un caso especial que se
aparta de estas reglas.

Los identificadores distinguen maysculas y minsculas, as que Sum, sum y suM son distintos
para el compilador. Sin embargo, C++Builder ofrece la opcin de suspender la sensibilidad a
maysculas / minsculas, lo que permite la compatibilidad con lenguajes insensibles a esta
cuestin, en este caso, las variables globales Sum, sum y suM seran consideradas idnticas,
aunque podra resultar un mensaje de aviso "Duplicate symbol" durante el enlazado.
2.1 Con los identificadores del tipo __pascal hay una excepcin a esta regla, ya que son
convertidos siempre a maysculas con vistas al enlazado.
Los identificadores globales importados desde otros mdulos siguen las mismas reglas que los
identificadores normales.

3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sealadas), se produce un error si se utiliza el mismo identificador dentro del mismo mbito
compartiendo el mismo espacio de nombres ( 4.1.11). Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de mbito.
Un identificador no puede coincidir con una palabra clave ( 3.2.1) o con el de ninguna
funcin de biblioteca.

4 El estndar ANSI distingue dos tipos de identificadores:
Identificadores internos; los nombres de macros de preprocesado y todas las que no
tengan enlazado externo. El estndar establece que sern significativos, al menos, los
primeros 31 caracteres.
Identificadores externos; los que corresponden a elementos que tengan enlazado
externo. En este caso el estndar es ms permisivo. Se acepta que el compilador
identifique solo seis caracteres significativos y pueda ignorar la distincin
maysculas/minsculas (Enlazado 1.4.4).
5 Reglas de estilo
Es bastante frecuente que en la enseanza de C++ (y de cualquier otro lenguaje de programacin)
no se subraye suficientemente la importancia de la eleccin de los identificadores. En este sentido,
los textos se suelen limitar a sealar las reglas formales que impone el lenguaje para la declaracin
de nombres. Sin embargo, como todos los que tienen que ver con la legibilidad del cdigo, el
asunto es de capital importancia. Sobre todo, si se trata de algo ms que del consabido programita
"Hola mundo", y desde luego resulta crtico en proyectos medianamente grandes en los que
puedan trabajar ms de un programador y/o deba ser mantenido por personas distintas de su
creador original (lo que antes o despus acaba ocurriendo en la informtica empresarial).
C y C++ tienen sus propias reglas no escritas, sancionadas por la costumbre, en cuanto a ciertas
formas concretas de usar los identificadores. Por ejemplo: Es costumbre utilizar minsculas para
los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minsculas/Maysculas - por ejemplo getRvalue o rColor-, aunque la inicial suele ser
minscula). Los identificadores de variables automticas lo ms cortos posibles (2); los de estticas
y globales ms largos y descriptivos (3). Los nombres de constantes simblicas normalmente en
maysculas (4).
Ejemplo:
void someFunc (int numero, char clave, int* puntero_a_clase); // (3)
static tipoCliente = 0; // (3)
enum formaPago { CONTADO, CREDITO }; // (4)
...
someFunc(int n, char k, int *ptr) { // (1) (2)
int z, y, z = 2; // (2)
}

Aparte de las manas o hbitos particulares que pueda tener cada programador, la mayora de
empresas de software medianamente serias disponen de sus propios "Manuales de estilo" o
"Reglas de uso", en los que se recogen las convenciones que deben utilizarse para los
identificadores, de forma que se mantenga la mxima homogeneidad posible en el cdigo, lo que a
la postre redunda en una mayor legibilidad y facilidad de mantenimiento. En este sentido cabra
sealar que, dentro de ciertos lmites, no es tan importante cuales sean estas reglas, sino que
existan y se respeten.
En determinados entornos existen reglas consagradas por el uso. Por ejemplo, en la programacin
C/C++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacin Hngara [5], en la que el identificador de cada variable comienza con una o varias
letras (minsculas) que sealan el tipo de la variable. Por ejemplo, nValor.
Los nombres de clases se preceden siempre con una "C" mayscula, y la siguiente letra tambin
es mayscula. Por ejemplo: CAboutDlg,CAprenderApp, CMainFrame, etc. Los nombres de
variables comienzan por letras fijas segn su tipo (ver cuadro adjunto), pero cuando se refieren a
una propiedad de clase, los dos primeros caracteres son "m_"
(ejemplo m_nValor, m_wndStatusBar, etc). Los nombres de funciones miembro de clase
comienzan siempre con mayscula, pero la siguiente letra es minscula [6]. Por
ejemplo: DoDataExchange(),InitInstance(), OnAppAbout(), etc.
Este tipo de notacin presenta la ventaja de con un poco de prctica es mucha la informacin que
puede extraerse de la simple lectura del cdigo.
En el cuadro adjunto se incluyen algunas de estas convenciones.
Prefijo Tipo de dato/situacin
Ejemplo
a
Matriz (array) aValor, aX, aY
b
BOOL (long) bValor, bA, bB
by
BYTE (unsigned char) byValr, byA, byB
c / ch
carcter (char) cValor, cA, cB, chA, chB
clr
COLORREF (unsigned long) [3] clrBgColor, clrFrgColor
cx, cy
Entero (short) [2] cxValor, cyValor, cxA, cyA
d
double dValor, dA, dB
dw
DWORD (unsigned long) dwValor, dwA, dwB
fn
Funcin normal (los mtodos siguen otra
regla)
fnGetx(), fnGety()
h
Handle [4] hWind, m_hWind
i
Entero (int) iValor, iX, iY
l
LONG (long) lValor, lX, lY
m_
Propiedades de clases (member variable) m_nValor, m_szString
n
Entero (short int) nValor, nX, nY
p
Puntero pValor, pA, pB
s
Cadena alfanumrica (string) sValor, sA, sB
sz Cadena alfanumrica terminada en
carcter nulo
al viejo estilo C ( 4.3.4)
szValor, szA, szB
u Entero (unsigned int)
uValor, uA, uB
x, y
Coordenadas x e y x, y
w
WORD (unsigned short) wValor, wA, wB
C
Clases ( 4.11) la letra siguiente
tambin mayscula
CDialog, CEditView, CButton

Nota: la programacin Windows utiliza sus propios tipos definidos mediante typedefs (
3.2.1a). Generalmente son identificadores expresados en maysculas ( Ejemplos).
3.2.3 Constantes
1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas,
que conviene distinguir:
1.1 La primera es el sentido normal de la palabra constante en lenguaje natural; es decir, datos
(de cualquiera de los tipos posible) cuyos valores se han definido en el momento de escribir el
cdigo del programa, y no pueden ser modificados ms tarde en tiempo de ejecucin (lo que
significa que sus valores deben ser resueltos en tiempo de compilacin). Dicho en otras
palabras: el compilador sabe cual es el valor de los objetos declarados como constantes y en base
a este conocimiento puede hacer cuantas suposiciones sean vlidas para conseguir la mayor
eficiencia en tiempo de ejecucin.
En este sentido, el concepto constante es justamente el opuesto a variable, que corresponde a
aquellos objetos-dato que pueden recibir nuevas asignaciones de valor a lo largo del
programa. Dicho en otras palabras: entidades cuyo valor solo es conocido en tiempo de ejecucin.
1.2 La segunda connotacin es la de tipo ( 2.1) de objeto-dato. En este sentido podemos
afirmar que en C++ los enteros (variables) forman un tipo distinto de los enteros constantes
(constantes enteras), y que los caracteres (variables) forman un tipo distinto de las constantes
carcter. As pues, distinguimos entre un tipo char y un tipo const char. Como prcticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes, existe un universo de
tipos C++, simtrico al de los tipos de objetos variables, pero de objetos constantes.
Como corolario de lo anterior, tenga en mente que, por ejemplo, un entero y una constante
entera son tipos distintos y que una constante entera C++ significa algo ms que un entero al que
no se le puede cambiar su valor.

2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende
de la implementacin. Esto significa que no est garantizado que tales objetos tengan un Lvalue (
2.1.5). Por ejemplo: en const int x = 5; no est garantizado que el compilador le asigne
a x un Lvalue, es decir, un espacio en memoria determinado (que se permita modificar o no su
valor es otra cuestin).
Puede ocurrir que, por razones de eficacia, sea simplemente una especie de "define" [1]. Una
especie de nemnico que hace que el compilador lo sustituya por un 5 en cada trozo de cdigo
donde aparezca x. Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacin. Por ejemplo, si en otro sitio del programa
aparece: const int z = 7; y ms tarde: int w = x + z + y;puede ocurrir que el
compilador establezca directamente: int w = 12 + y.
Por esta razn no est garantizado que el operador const_cast ( 4.9.9a) funcione con objetos
declarados inicialmente como constantes.

3 Como se ha indicado, en C++ existen tantos tipos de constantes como tipos de variables, pero
aparte de las ya mencionadas constantes manifiestas ( 1.4.1a), solo nos detendremos en las
que por una u otra razn hay cosas interesantes que puntualizar. Son las siguientes:
Expresiones Constantes ( 3.2.3a)
Constantes enteras ( 3.2.3b)
Constantes fraccionarias ( 3.2.3c)
Constantes carcter de varios subtipos, incluyendo elementos aislados y cadenas (
3.2.3d, 3.3.3h, 3.2.3f)
Enumeraciones ( 3.2.3g)
El Estndar C++ denomina "literales" a lo que el Estndar C denomina "constantes", y establece
que existen 5 tipos de estos "literales":
Constantes enteras ("Integer literal")
Constantes carcter ("Character literal")
Constantes fraccionarias ("Floating literal")
Constantes de cadena ("String literal")
Constantes lgicas ("Boolean literal").

4 Por la forma en que estn expresadas en el cdigo pueden considerarse en dos grupos:
Directas si estn directamente expresadas. Por ejemplo:
const float pi = 3.14159;
Expresiones ( 3.2.3a) si su valor est implcito en una expresin. Por ejemplo:
const float k = pi * 2;

5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a
indicios implcitos, como el valor numrico y formato usados en el fuente. En algunos casos
tambin por ciertos calificadores explcitos. C++ tiene una palabra especfica para este fin: const (
3.2.1c).
Ejemplos:
char c = 'X'; // X es una constante tipo char
const int X = 10; // X es un tipo int-constante
Inicio.

[1] De hecho, en los primitivas versiones del C de K&R, cuando se quera utilizar una constante
haba que utilizar un define ( 4.9.10b) en la forma:
# define PI = 3.13159;
# define G = 9.80665;
Etc.
3.2.3a Expresiones constantes
1 Sinopsis
Una expresin constante es aquella que solo implica a constantes (queda reducida a una
constante), por lo que puede ser evaluada en tiempo de compilacin y debe evaluarse a un valor
que est en el rango de valores admitidos para el tipo que se declara. Por ejemplo, si estamos
declarando una constante tipo int, la expresin debe reducirse a un int:
int const peso = 50 + 20;
Los operandos de las expresiones constantes pueden ser constantes enteras ( 3.2.3b);
constantes carcter ( 3.2.3d); constantes fraccionarias ( 3.2.3c); constantes de enumeracin (
3.2.3g); expresiones sizeof ( 4.9.13); expresiones de modelado de tipos ( 4.9.9), e incluso
otras expresiones constantes, aunque en ciertos casos se imponen algunas restricciones .
Las expresiones constantes se evalan como el resto de las expresiones con variables y pueden
utilizarse en cualquier caso en que sea legal el uso de una constante.
2 Sintaxis
expresion-constante:
Expresion-condicional
3 Ejemplo
#define LEAP 1 /* en aos bisiestos */
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31];

4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacin a menos que los operadores estn contenidos dentro del operando de un
operador sizeof ( 4.9.13).
Asignacin int const k = 2+(kte = 4); // Error
Coma int const k = (i=1, 3); // Error
Decremento int const k = kte--; // Error
Llamada a funcin int const k = func(4); // Error
Incremento int const k = kte++; // Error

5 Existen mltiples situaciones en las que el compilador C++ exige la presencia de expresiones
constantes enteras (que se resuelvan a un entero). Por ejemplo, para establecer el tamao del
campo de bits de una estructura ( 4.5.9); el valor de una constante de enumeracin (
3.2.3g); el tamao de una matriz ( 4.3.1) o el valor de una constante case ( 4.10.2).
6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4.9.10d) estn sujetas a
ciertas restricciones adicionales, por lo que son conocidas como expresiones constantes
restringidas. Entre estas restricciones se encuentran que no pueden contener constantes
fraccionarias; tampoco expresiones sizeof, constantes de enumeracin ni expresiones de
modelado de tipo.
3.2.3b Constantes enteras
1 Sinopsis
Las constantes enteras representan un int, y pueden estar expresadas en los sistemas de
numeracin decimal ; octal o hexadecimal . En ausencia de ningn sufijo , el tipo de
una constante entera se deduce de su valor segn se muestra en las tablas que siguen. Observe
que las reglas para las constantes decimales son distintas del resto.
2 Decimal
Se permiten constantes enteras en formato decimal (base 10, 2.2.4b) dentro del rango 0 a
4,294,967,295; las que excedan este lmite sern truncadas. Observe que las constantes
decimales no pueden comenzar con cero, porque seran interpretadas como octales.
int i = 10; // decimal 10
int i = 010; // decimal 8 (octal 10)
int i = 0; // decimal 0 = octal 0

Tipos adoptados por las constantes decimales en funcin del valor declarado (en ausencia de
sufijos L o U)
0 a 32,767 int
32,768 a 2,147,483,647 long
2,147,483,648 a 4,294,967,295 unsigned long
>4294967295 truncado
3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8, 2.2.4b). Si una
constante de este tipo contiene dgitos ilegales (8 o 9), se produce un mensaje de error; como se
indica en la tabla adjunta, las que exceden del valor mximo 037777777777 son truncadas.
Tipos adoptados por las constantes Octales en funcin del valor declarado (en ausencia de
sufijos L o U).
00 a 077777 int
010000 a 0177777 unsigned int
02000000 a 017777777777 long
020000000000 a 037777777777 unsigned long
> 037777777777 truncado
4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1], base 16 (
2.2.4b), despus se pueden incluir los dgitos vlidos (0...9, a...f, A...F). Como se indica e el
cuadro adjunto, las que excedan del valor mximo 0xFFFFFFFF son truncadas.
Tipos adoptados por las constantes hexadecimales en funcin del valor declarado (en ausencia
de sufijos L o U).
0x0000 a 0x7FFF int
0x8000 a 0xFFFF unsigned int
0x10000 a 0x7FFFFFFF long
0x80000000 a 0xFFFFFFFF unsigned long
>0xFFFFFFFF truncado
Ejemplo:
long lg1 = 0xFFFF; lg2 = 0xFF;
cout << lg1 << endl; // -> 65535
cout << lg2 << endl; // -> 255
#define CS_VREDRAW 0x0001
#define CS_HREDRAW 0x0002
5 Sufijos: long (L) y unsigned (U)
La adicin de sufijos en la definicin de una constante puede forzar que esta sea de un tipo
especfico, as pues, los sufijos funcionan como una especie de "casting" para las constantes. Se
utilizan las letras U u L l. Estos sufijos se pueden utilizar juntos y en cualquier orden o grafa (ul,
lu, Ul, lU, uL, Lu, LU o UL).
Los sufijos L / l despus de una constante la fuerzan a ser declarada como long. Ejemplo:
const x = 7L; // x es long
Los sufijos U / u la fuerzan a que sea declarada como unsigned; en este caso, con
independencia de la base utilizada, la constante ser considerada unsigned long si el valor del
nmero es mayor que el decimal 65,535. Ejemplo:
const x = 7U; // x es unsigned int
const y = 66000U; // y es unsigned long

En ausencia de alguno de estos sufijos el tipo de la constante es el primero de los que se
sealan que pueda albergar su valor.
Decimal: int, long int, unsigned long int
Octal: int, unsigned int, long int, unsigned long int
Hexadecimal: int, unsigned int, long int, unsigned long int

Si la constante tiene un sufijo U o u, su tipo es unsigned int, unsigned long o int (el primero
que pueda albergar el valor).
Si tiene un sufijo L o l, su tipo es long int o unsigned long int (el primero que pueda albergar
el valor).
Si la constante tiene ambos sufijos, u e l (ul, lu, Ul, lU, uL, Lu, LU o UL), su tipo de
es unsigned long int. Ejemplo:
const z = 0UL; // z es unsigned long

Como puede verse, las constantes enteras sin L o U compendian la representacin de constantes
enteras en cualquiera de los tres sistemas de numeracin (en C++Builder).
Nota: algunos compiladores utilizan los sufijos ll/LL y ull/ULL para referirse a los enteros
extendidos ( 3.2.3d) long long y unsigned long long respectivamente.
3.2.3c Constantes fraccionarias
1 Sinopsis
Las constantes fraccionarias (tambin llamada "de punto flotante") corresponden al concepto
matemtico de nmeros fraccionarios. Es decir, cantidades con cierto nmero de cifras
decimales. Su representacin el cdigo fuente puede contener:
Parte entera 37.092e-2L
Punto decimal [1] 37.092e-2L
Parte fraccionaria 37.092e-2L
e/E y un entero con signo (exponente) 37.092e-2L.
Sufijo (indicador de tipo): f/F l/L 37.092e-2L

Pueden omitirse la parte entera o la decimal (pero no ambas); pueden omitirse el punto decimal y
la letra E (e), y el exponente (pero no ambos). Las constantes fraccionarias negativas se forman
igual que las positivas, pero precedindolas con el operador unitario menos ( - ).
2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacin:
Notacin convencional (de punto decimal)
Notacin cientfica (con exponente E/e)
Ejemplos:
Expresin Valor
23.45e6 23.45 10^6
.0 0
0. 0.0
1. 1.0
-1.23 -1.23
2e-5 2.0 10^-5
3E+10 3.0 10^10
.09E34 0.09 10^34
Nota: la notacin 10^-5 significa 10 elevado a menos 5 ( 10
-5
).
Ms informacin sobre la notacin cientfica en ( 2.2.4a)

3 En ausencia de cualquier sufijo, las constantes fraccionarias se consideran de
tipo double, aunque se puede obligar a que sea considerada de tipo float aadindole el
sufijo f F.
Ejemplo:
x = 1.; // L.1:
y = 1.f; // L.2:
En L.1 la constante 1.0 es considerada double, y podra producir una advertencia del
compilador: Warning: Initializacin to 'int' from 'double'.
L.2 producira: Warning: Initializacin to 'int' from 'float'. La razn es que, por
tradicin del C, en ausencia de una declaracin explcita de tipo, en expresiones como L.1 y L.2, el
compilador C++ supone que x e y son tipo int.
Ejemplo relacionado: ( 2.2.4a)

4 De forma anloga, el sufijo l / L la fuerza a ser del tipo long double.
Ejemplo:
long lg1 = 3.0; // L.1:
long lg2 = 3.2L; // L.2:
long double = 4.0L; // L.3: Ok.
En L.1el compilador puede mostrar un aviso: Warning: initialization to 'long int'
from 'double'. En L.2 el aviso sera:Warning: initialization to 'long int' from
'long double'.

5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles: float, double y long double.
Tipo Tamao (bits) Rango .
float 32 3.4 10^-38 a 3.4 10^38
double 64 1.7 10^-308 a 1.7 10^308
long double 80 3.4 10^-4932 a 1.1 10^4932


3.2.3d Constantes carcter
1 Sinopsis
Una constante carcter es uno o ms caracteres delimitados por comillas simples, como 'A', '+',
o '\n'. En C++, son de un tipo especfico: chardel que existen dos
versiones, signed y unsigned [1]. El valor por defecto, el que se supone cuando no se indica
nada en concreto (char a secas) depende del compilador, pero puede ser seleccionado.
2 Los tres tipos char
Las constantes de un carcter, tales como 'A', '\t' y '007', son representados como valores
enteros, int (signed). En estos casos, si el valor es mayor que 127, el bit ms alto es puesto a -1 (
= 0xFF), es decir, las constantes carcter cuyo valor ASCII es mayor de 127 se representan como
nmeros negativos, aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto.
Cualquiera de los tres tipos carcter, char, signed char y unsigned char, se almacenan en 8-bits
(un byte) [2].

En los programas a C++, una funcin puede ser sobrecargada con argumentos de cualquiera de
los tres tipos: char, signed char o unsigned char (porque son tipos distintos para el compilador).
Por ejemplo, los siguientes prototipos de funciones son vlidos y distintos:
void func(char ch);
void func(signed char ch);
void func(unsigned char ch);

Sin embargo, si existiera solo uno de dichos prototipos, podra aceptar cualquiera de los tres tipos
carcter. Por ejemplo, el cdigo que sigue sera aceptable (se producira una conversin
automtica de tipo al pasar el argumento a la funcin):
void func(unsigned char ch);

void main(void) {
signed char ch = 'x';
func(ch);
}
3 Constantes de carcter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los carcter normales (char, signed char o unsigned char).
Nota histrica: en C clsico, un carcter ancho ocupa dos bytes, y cualquier constante carcter
precedida por L es un carcter ancho, un tipo de dato denominado wchar_t, que en realidad es
un typedef definido en <stddef.h>.
En Borland C++ wchar_t est definida como: typedef unsigned short wchar_t; para el
caso de compilar como C. Recuerde que este compilador puede trabaja indistintamente con cdigo
C y C++, y que un unsigned short ocupa 2 bytes ( 2.2.4).

En C++ wchar_t es una palabra clave que representa un tipo especial, el carcter ancho o
extendido. Su espacio de almacenamiento depende de la implementacin (ver 2.2.1a1). En el
caso de BC++ 5.5 ocupa el mismo espacio que un int, es decir: 4 bytes. En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por carcter.
Ejemplos:
wchar_t ch = L'A';
wchar_t *str = L"ABCD";
wchar_t nulo = L'\0' // carcter nulo ancho


423

También podría gustarte