06 Programacion en c++
Transcript of 06 Programacion en c++
sect3 Identificacioacuten del endianness del sistema
Si estamos escribiendo una aplicacioacuten o libreriacutea muy general que en alguacuten punto deba tener en
cuenta el endiannes de la maacutequina anfitriona es posible averiguarlo faacutecilmente mediante una
directiva que podemos utilizar posteriormente en las sentencias correspondientes seguacuten el resultado Seriacutean las siguientes
const unsigned int myOne = 1
define IS_BIGENDIAN ((char)(ampmyOne) == 0)
define IS_LITTLEENDIAN ((char)(ampmyOne) == 1)
Observe que la direccioacuten de myOne (que es un puntero-a-int) es convertida a puntero-a-
char mediante el cast correspondiente a continuacioacuten se compara el contenido de esta direccioacuten
con cero y con 1 En realidad se estaacute comparando el primer bite de myOne El truco estaacute
precisamente en comparar el contenido del primer byte (la comparacioacuten myOne == 1 seriacutea
siempre cierta) El resultado es 0 (falso) o 1 (cierto) seguacuten el modelo del sistema utilizado que corresponderaacute o no con el del hardware subyacente seguacuten el caso Por ejemplo en una maacutequina IntelampWindows el programa
include ltcstdlibgt
include ltiostreamgt
const unsigned int myOne = 1
define IS_BIGENDIAN ((char)(ampmyOne) == 0)
define IS_LITTLEENDIAN ((char)(ampmyOne) == 1)
int main(int argc char argv[])
stdcout ltlt Esta maquina es Big-endian ltlt
(IS_BIGENDIAN Cierto Falso) ltlt stdendl
stdcout ltlt Esta maquina es Little-endian ltlt
(IS_LITTLEENDIAN Cierto Falso) ltlt stdendl
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 leacutexicos
In the software professions reading is like breathing Stopping can be dangerous to your health David Weber CC++ Users Journal Marzo 1996 Twho C++ tutorials
sect1 Sinopsis
Los elementos que componen el lenguaje C++ los podemos dividir en dos grandes grupos
Comentarios que como veremos son eliminados por el preprocesador ( 31)
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 propoacutesitos
especiales y no deben ser utilizadas como identificadores ( 321)
Identificadores tambieacuten llamados etiquetas Son nombres arbitrarios de cualquier longitud
que sirven para identificar los objetos ( 322)
Constantes Datos que estaacuten definidos en el programa y que no pueden ser modificados a lo
largo del mismo ( 323)
Operadores Un tipo de tokens que pueden aparecer en las expresiones e indican al
compilador la realizacioacuten de determinadas operaciones matemaacuteticas ( 49)
Puntuadores Signos de puntuacioacuten anaacutelogos a los utilizados en el lenguaje corriente (
326)
31 Comentarios
Remember comments are for humans so write them that way Aaron Weiss JavaScript Tutorial for Programmers
sect1 Sinopsis
Comentarios son anotaciones observaciones recordatorios etc en el programa Son para uso exclusivo del programador y eliminados del coacutedigo fuente en la fase de preprocesado antes
del anaacutelisis sintaacutectico ( 14)
Aparte de las consideraciones estrictamente formales que se indican en esta seccioacuten no debemos perder de vista que los comentarios aunque voluntarios (no es obligatorio escribirlos) representan una ayuda inestimable durante la construccioacuten del programa Siendo imprescindibles para el programador original o los que le sucedan en las tareas de mantenimiento cuando es necesario habeacuterselas con el coacutedigo un tiempo despueacutes de que fue escrito Ademaacutes de clarificar ideas los comentarios son tambieacuten un valioso instrumento de depuracioacuten pues permiten eliminar provisionalmente secciones enteras de coacutedigo
En C++ coexisten dos formas de comentarios El de C claacutesico y el de C++ Ambos son soportados por C++Builder que tiene ademaacutes una extensioacuten particular sobre el estaacutendar ANSI los comentarios anidados (este uacuteltimo tipo solo debe usarse si la compatibilidad no es importante)
Tambieacuten 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
sect2 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 despueacutes de la expansioacuten de macros (algunas implementaciones de C pueden eliminar los comentarios sin reemplazarlos por espacios)
Ejemplo
int x = 2 esto es un comentario que seraacute eliminado o sustituido
por un simple espacio despueacutes en la frase de preprocesado Como puede
verse el comentario puede ocupar varias liacuteneas de texto en el coacutedigo
fuente
Se recomienda utilizarlos con profusioacuten a veces todas las explicaciones
son pocas ya que el C++ es un lenguaje bastante criacuteptico en algunas
ocasiones sobre todo algunas sentencias muy elegantes y comprimidas
pero ininteligibles en una primera lectura
Ejemplo la expresioacuten
int declaracioacuten i contador
es analizada sintaacutecticamente como estos tres tokens int i y
sect3 Pegado de cadenas
Algunos compiladores C claacutesicos utilizan el siacutembolo para el pegado (concatenado) de tokens
pero el nuevo Estaacutendar ANSI recomienda que esto se haga con (ver ejemplos)
El pegado de tokens es una teacutecnica que utiliza las habilidades de preprocesador para construir
nombres nuevos utilizando macros ( 4910b) Por ejemplo
define VAR(ij) (ij) Incorrecto
define VAR(ij) (ij) Correcto
define VAR(ij) (i j) Correcto
Despueacutes 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()
sect4 Comentarios C++
C++ admite comentarios de una sola liacutenea utilizando dos barras inclinadas ( ) como sentildeal de
comienzo El comentario empieza en este punto (incluyendo las sentildeales de comienzo) y continuacutea hasta el proacuteximo caraacutecter de nueva linea
class X esto es un comentario
sect5 Comentarios anidados
El estaacutendar ANSI C no permite la existencia de comentarios anidados [1] Por ejemplo no podemos utilizar el comentario
int declaracioacuten i contador
porque el aacutembito del primer termina en el primer por lo que se obtiene i lo que
produciriacutea un error de sintaxis
sect6 Delimitadores y espacios
En casos raros algunos espacios antes de y despueacutes de aunque no sean
sintaacutecticamente imprescindibles deben ponerse para evitar posibles problemas de portabilidad Por ejemplo en este coacutedigo
int i = j divide por kk
+m
es analizado sintaacutecticamente como
int i = j +m
no como
int i = jk
+m
que seriacutea lo esperado seguacuten las reglas de C La forma que sigue (maacutes legible) evitariacutea este problema
int i = j divide por k k
+m
32 Tokens
sect1 Sinopsis
El tratar de la estructura loacutegica de un programa ( 131) se sentildealoacute que tokens son los elementos
en que el preprocesado desmenuza el coacutedigo fuente En un lenguaje de programacioacuten los tokens son el equivalente a las palabras y signos de puntuacioacuten en el lenguaje natural escrito Los tokens
estaacuten separados por elementos de separacioacuten que reciben el nombre geneacuterico de separadores (
14)
Comprenden los siguientes tipos de elementos (podriacuteamos 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 sentildealadas en ( 321)
Identificadores Su nuacutemero puede ser virtualmente infinito dentro de ciertas normas el
programador es libre de elegir los que mejor se ajusten a sus necesidades( 322)
Constantes Existen varias clases cuyos detalles se exponen en las paacuteginas siguientes (
323)
operadores ( 49)
signos de puntuacioacuten tambieacuten llamados puntuadores ( 326)
En ocasiones los operadores y signos de puntuacioacuten comparten la misma representacioacuten
escrita En estos casos el sentido debe deducirse del contexto y por la forma en que estaacuten agrupados los diversos signos
El conjunto de siacutembolos grupos de siacutembolos y palabras utilizados en C++ como operadores yo puntuadores es el siguiente (los operadores se han sentildealado en azul)
[ ] ( )
lt gt lt gt
+ - ^ amp | ~
= lt gt += -= = = =
^= amp= |= ltlt gtgt gtgt= ltlt= == =
lt= gt= ampamp || ++ -- -gt -gt
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 sintaacutectico (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
321 Palabras clave
sect1 Sinopsis
Las palabras clave (Keywords) son identificadores utilizados por el lenguaje para fines
especiales y no pueden ser utilizadas como identificadores (por esta razoacuten se suelen denominar tambieacuten palabras reservadas) Por ejemplo no pueden ser utilizadas como nombres de variables clases o funciones
El primitivo C de Kerningham y Ritchie teniacutea solo 27 el C estaacutendar las amplioacute a 32 y C++ antildeadioacute algunas maacutes Hay que advertir que aunque el Estaacutendar C++ define perfectamente cuales son las palabras reservadas incluidas a continuacioacuten 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 opcioacuten -A de compilacioacuten (
143) que permite forzar las reglas a ANSI C++ estricto con el fin de conseguir un coacutedigo
lo maacutes portable posible Con esta opcioacuten las palabras clave no estrictamente ANSI son ignoradas como tales El resto de compiladores (MS Visual y GCC) tienen opciones similares
sect2 Palabras clave del C++ Estaacutendar
Keyword referencia Keyword referencia Keyword referencia
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
sect1 Sinopsis
Los elementos que componen el lenguaje C++ los podemos dividir en dos grandes grupos
Comentarios que como veremos son eliminados por el preprocesador ( 31)
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 propoacutesitos
especiales y no deben ser utilizadas como identificadores ( 321)
Identificadores tambieacuten llamados etiquetas Son nombres arbitrarios de cualquier longitud
que sirven para identificar los objetos ( 322)
Constantes Datos que estaacuten definidos en el programa y que no pueden ser modificados a lo
largo del mismo ( 323)
Operadores Un tipo de tokens que pueden aparecer en las expresiones e indican al
compilador la realizacioacuten de determinadas operaciones matemaacuteticas ( 49)
Puntuadores Signos de puntuacioacuten anaacutelogos a los utilizados en el lenguaje corriente (
326)
31 Comentarios
Remember comments are for humans so write them that way Aaron Weiss JavaScript Tutorial for Programmers
sect1 Sinopsis
Comentarios son anotaciones observaciones recordatorios etc en el programa Son para uso exclusivo del programador y eliminados del coacutedigo fuente en la fase de preprocesado antes
del anaacutelisis sintaacutectico ( 14)
Aparte de las consideraciones estrictamente formales que se indican en esta seccioacuten no debemos perder de vista que los comentarios aunque voluntarios (no es obligatorio escribirlos) representan una ayuda inestimable durante la construccioacuten del programa Siendo imprescindibles para el programador original o los que le sucedan en las tareas de mantenimiento cuando es necesario habeacuterselas con el coacutedigo un tiempo despueacutes de que fue escrito Ademaacutes de clarificar ideas los comentarios son tambieacuten un valioso instrumento de depuracioacuten pues permiten eliminar provisionalmente secciones enteras de coacutedigo
En C++ coexisten dos formas de comentarios El de C claacutesico y el de C++ Ambos son soportados por C++Builder que tiene ademaacutes una extensioacuten particular sobre el estaacutendar ANSI los comentarios anidados (este uacuteltimo tipo solo debe usarse si la compatibilidad no es importante)
Tambieacuten 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
sect2 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 despueacutes de la expansioacuten de macros (algunas implementaciones de C pueden eliminar los comentarios sin reemplazarlos por espacios)
Ejemplo
int x = 2 esto es un comentario que seraacute eliminado o sustituido
por un simple espacio despueacutes en la frase de preprocesado Como puede
verse el comentario puede ocupar varias liacuteneas de texto en el coacutedigo
fuente
Se recomienda utilizarlos con profusioacuten a veces todas las explicaciones
son pocas ya que el C++ es un lenguaje bastante criacuteptico en algunas
ocasiones sobre todo algunas sentencias muy elegantes y comprimidas
pero ininteligibles en una primera lectura
Ejemplo la expresioacuten
int declaracioacuten i contador
es analizada sintaacutecticamente como estos tres tokens int i y
sect3 Pegado de cadenas
Algunos compiladores C claacutesicos utilizan el siacutembolo para el pegado (concatenado) de tokens
pero el nuevo Estaacutendar ANSI recomienda que esto se haga con (ver ejemplos)
El pegado de tokens es una teacutecnica que utiliza las habilidades de preprocesador para construir
nombres nuevos utilizando macros ( 4910b) Por ejemplo
define VAR(ij) (ij) Incorrecto
define VAR(ij) (ij) Correcto
define VAR(ij) (i j) Correcto
Despueacutes 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()
sect4 Comentarios C++
C++ admite comentarios de una sola liacutenea utilizando dos barras inclinadas ( ) como sentildeal de
comienzo El comentario empieza en este punto (incluyendo las sentildeales de comienzo) y continuacutea hasta el proacuteximo caraacutecter de nueva linea
class X esto es un comentario
sect5 Comentarios anidados
El estaacutendar ANSI C no permite la existencia de comentarios anidados [1] Por ejemplo no podemos utilizar el comentario
int declaracioacuten i contador
porque el aacutembito del primer termina en el primer por lo que se obtiene i lo que
produciriacutea un error de sintaxis
sect6 Delimitadores y espacios
En casos raros algunos espacios antes de y despueacutes de aunque no sean
sintaacutecticamente imprescindibles deben ponerse para evitar posibles problemas de portabilidad Por ejemplo en este coacutedigo
int i = j divide por kk
+m
es analizado sintaacutecticamente como
int i = j +m
no como
int i = jk
+m
que seriacutea lo esperado seguacuten las reglas de C La forma que sigue (maacutes legible) evitariacutea este problema
int i = j divide por k k
+m
32 Tokens
sect1 Sinopsis
El tratar de la estructura loacutegica de un programa ( 131) se sentildealoacute que tokens son los elementos
en que el preprocesado desmenuza el coacutedigo fuente En un lenguaje de programacioacuten los tokens son el equivalente a las palabras y signos de puntuacioacuten en el lenguaje natural escrito Los tokens
estaacuten separados por elementos de separacioacuten que reciben el nombre geneacuterico de separadores (
14)
Comprenden los siguientes tipos de elementos (podriacuteamos 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 sentildealadas en ( 321)
Identificadores Su nuacutemero puede ser virtualmente infinito dentro de ciertas normas el
programador es libre de elegir los que mejor se ajusten a sus necesidades( 322)
Constantes Existen varias clases cuyos detalles se exponen en las paacuteginas siguientes (
323)
operadores ( 49)
signos de puntuacioacuten tambieacuten llamados puntuadores ( 326)
En ocasiones los operadores y signos de puntuacioacuten comparten la misma representacioacuten
escrita En estos casos el sentido debe deducirse del contexto y por la forma en que estaacuten agrupados los diversos signos
El conjunto de siacutembolos grupos de siacutembolos y palabras utilizados en C++ como operadores yo puntuadores es el siguiente (los operadores se han sentildealado en azul)
[ ] ( )
lt gt lt gt
+ - ^ amp | ~
= lt gt += -= = = =
^= amp= |= ltlt gtgt gtgt= ltlt= == =
lt= gt= ampamp || ++ -- -gt -gt
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 sintaacutectico (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
321 Palabras clave
sect1 Sinopsis
Las palabras clave (Keywords) son identificadores utilizados por el lenguaje para fines
especiales y no pueden ser utilizadas como identificadores (por esta razoacuten se suelen denominar tambieacuten palabras reservadas) Por ejemplo no pueden ser utilizadas como nombres de variables clases o funciones
El primitivo C de Kerningham y Ritchie teniacutea solo 27 el C estaacutendar las amplioacute a 32 y C++ antildeadioacute algunas maacutes Hay que advertir que aunque el Estaacutendar C++ define perfectamente cuales son las palabras reservadas incluidas a continuacioacuten 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 opcioacuten -A de compilacioacuten (
143) que permite forzar las reglas a ANSI C++ estricto con el fin de conseguir un coacutedigo
lo maacutes portable posible Con esta opcioacuten las palabras clave no estrictamente ANSI son ignoradas como tales El resto de compiladores (MS Visual y GCC) tienen opciones similares
sect2 Palabras clave del C++ Estaacutendar
Keyword referencia Keyword referencia Keyword referencia
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Tambieacuten 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
sect2 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 despueacutes de la expansioacuten de macros (algunas implementaciones de C pueden eliminar los comentarios sin reemplazarlos por espacios)
Ejemplo
int x = 2 esto es un comentario que seraacute eliminado o sustituido
por un simple espacio despueacutes en la frase de preprocesado Como puede
verse el comentario puede ocupar varias liacuteneas de texto en el coacutedigo
fuente
Se recomienda utilizarlos con profusioacuten a veces todas las explicaciones
son pocas ya que el C++ es un lenguaje bastante criacuteptico en algunas
ocasiones sobre todo algunas sentencias muy elegantes y comprimidas
pero ininteligibles en una primera lectura
Ejemplo la expresioacuten
int declaracioacuten i contador
es analizada sintaacutecticamente como estos tres tokens int i y
sect3 Pegado de cadenas
Algunos compiladores C claacutesicos utilizan el siacutembolo para el pegado (concatenado) de tokens
pero el nuevo Estaacutendar ANSI recomienda que esto se haga con (ver ejemplos)
El pegado de tokens es una teacutecnica que utiliza las habilidades de preprocesador para construir
nombres nuevos utilizando macros ( 4910b) Por ejemplo
define VAR(ij) (ij) Incorrecto
define VAR(ij) (ij) Correcto
define VAR(ij) (i j) Correcto
Despueacutes 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()
sect4 Comentarios C++
C++ admite comentarios de una sola liacutenea utilizando dos barras inclinadas ( ) como sentildeal de
comienzo El comentario empieza en este punto (incluyendo las sentildeales de comienzo) y continuacutea hasta el proacuteximo caraacutecter de nueva linea
class X esto es un comentario
sect5 Comentarios anidados
El estaacutendar ANSI C no permite la existencia de comentarios anidados [1] Por ejemplo no podemos utilizar el comentario
int declaracioacuten i contador
porque el aacutembito del primer termina en el primer por lo que se obtiene i lo que
produciriacutea un error de sintaxis
sect6 Delimitadores y espacios
En casos raros algunos espacios antes de y despueacutes de aunque no sean
sintaacutecticamente imprescindibles deben ponerse para evitar posibles problemas de portabilidad Por ejemplo en este coacutedigo
int i = j divide por kk
+m
es analizado sintaacutecticamente como
int i = j +m
no como
int i = jk
+m
que seriacutea lo esperado seguacuten las reglas de C La forma que sigue (maacutes legible) evitariacutea este problema
int i = j divide por k k
+m
32 Tokens
sect1 Sinopsis
El tratar de la estructura loacutegica de un programa ( 131) se sentildealoacute que tokens son los elementos
en que el preprocesado desmenuza el coacutedigo fuente En un lenguaje de programacioacuten los tokens son el equivalente a las palabras y signos de puntuacioacuten en el lenguaje natural escrito Los tokens
estaacuten separados por elementos de separacioacuten que reciben el nombre geneacuterico de separadores (
14)
Comprenden los siguientes tipos de elementos (podriacuteamos 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 sentildealadas en ( 321)
Identificadores Su nuacutemero puede ser virtualmente infinito dentro de ciertas normas el
programador es libre de elegir los que mejor se ajusten a sus necesidades( 322)
Constantes Existen varias clases cuyos detalles se exponen en las paacuteginas siguientes (
323)
operadores ( 49)
signos de puntuacioacuten tambieacuten llamados puntuadores ( 326)
En ocasiones los operadores y signos de puntuacioacuten comparten la misma representacioacuten
escrita En estos casos el sentido debe deducirse del contexto y por la forma en que estaacuten agrupados los diversos signos
El conjunto de siacutembolos grupos de siacutembolos y palabras utilizados en C++ como operadores yo puntuadores es el siguiente (los operadores se han sentildealado en azul)
[ ] ( )
lt gt lt gt
+ - ^ amp | ~
= lt gt += -= = = =
^= amp= |= ltlt gtgt gtgt= ltlt= == =
lt= gt= ampamp || ++ -- -gt -gt
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 sintaacutectico (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
321 Palabras clave
sect1 Sinopsis
Las palabras clave (Keywords) son identificadores utilizados por el lenguaje para fines
especiales y no pueden ser utilizadas como identificadores (por esta razoacuten se suelen denominar tambieacuten palabras reservadas) Por ejemplo no pueden ser utilizadas como nombres de variables clases o funciones
El primitivo C de Kerningham y Ritchie teniacutea solo 27 el C estaacutendar las amplioacute a 32 y C++ antildeadioacute algunas maacutes Hay que advertir que aunque el Estaacutendar C++ define perfectamente cuales son las palabras reservadas incluidas a continuacioacuten 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 opcioacuten -A de compilacioacuten (
143) que permite forzar las reglas a ANSI C++ estricto con el fin de conseguir un coacutedigo
lo maacutes portable posible Con esta opcioacuten las palabras clave no estrictamente ANSI son ignoradas como tales El resto de compiladores (MS Visual y GCC) tienen opciones similares
sect2 Palabras clave del C++ Estaacutendar
Keyword referencia Keyword referencia Keyword referencia
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
C++ admite comentarios de una sola liacutenea utilizando dos barras inclinadas ( ) como sentildeal de
comienzo El comentario empieza en este punto (incluyendo las sentildeales de comienzo) y continuacutea hasta el proacuteximo caraacutecter de nueva linea
class X esto es un comentario
sect5 Comentarios anidados
El estaacutendar ANSI C no permite la existencia de comentarios anidados [1] Por ejemplo no podemos utilizar el comentario
int declaracioacuten i contador
porque el aacutembito del primer termina en el primer por lo que se obtiene i lo que
produciriacutea un error de sintaxis
sect6 Delimitadores y espacios
En casos raros algunos espacios antes de y despueacutes de aunque no sean
sintaacutecticamente imprescindibles deben ponerse para evitar posibles problemas de portabilidad Por ejemplo en este coacutedigo
int i = j divide por kk
+m
es analizado sintaacutecticamente como
int i = j +m
no como
int i = jk
+m
que seriacutea lo esperado seguacuten las reglas de C La forma que sigue (maacutes legible) evitariacutea este problema
int i = j divide por k k
+m
32 Tokens
sect1 Sinopsis
El tratar de la estructura loacutegica de un programa ( 131) se sentildealoacute que tokens son los elementos
en que el preprocesado desmenuza el coacutedigo fuente En un lenguaje de programacioacuten los tokens son el equivalente a las palabras y signos de puntuacioacuten en el lenguaje natural escrito Los tokens
estaacuten separados por elementos de separacioacuten que reciben el nombre geneacuterico de separadores (
14)
Comprenden los siguientes tipos de elementos (podriacuteamos 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 sentildealadas en ( 321)
Identificadores Su nuacutemero puede ser virtualmente infinito dentro de ciertas normas el
programador es libre de elegir los que mejor se ajusten a sus necesidades( 322)
Constantes Existen varias clases cuyos detalles se exponen en las paacuteginas siguientes (
323)
operadores ( 49)
signos de puntuacioacuten tambieacuten llamados puntuadores ( 326)
En ocasiones los operadores y signos de puntuacioacuten comparten la misma representacioacuten
escrita En estos casos el sentido debe deducirse del contexto y por la forma en que estaacuten agrupados los diversos signos
El conjunto de siacutembolos grupos de siacutembolos y palabras utilizados en C++ como operadores yo puntuadores es el siguiente (los operadores se han sentildealado en azul)
[ ] ( )
lt gt lt gt
+ - ^ amp | ~
= lt gt += -= = = =
^= amp= |= ltlt gtgt gtgt= ltlt= == =
lt= gt= ampamp || ++ -- -gt -gt
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 sintaacutectico (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
321 Palabras clave
sect1 Sinopsis
Las palabras clave (Keywords) son identificadores utilizados por el lenguaje para fines
especiales y no pueden ser utilizadas como identificadores (por esta razoacuten se suelen denominar tambieacuten palabras reservadas) Por ejemplo no pueden ser utilizadas como nombres de variables clases o funciones
El primitivo C de Kerningham y Ritchie teniacutea solo 27 el C estaacutendar las amplioacute a 32 y C++ antildeadioacute algunas maacutes Hay que advertir que aunque el Estaacutendar C++ define perfectamente cuales son las palabras reservadas incluidas a continuacioacuten 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 opcioacuten -A de compilacioacuten (
143) que permite forzar las reglas a ANSI C++ estricto con el fin de conseguir un coacutedigo
lo maacutes portable posible Con esta opcioacuten las palabras clave no estrictamente ANSI son ignoradas como tales El resto de compiladores (MS Visual y GCC) tienen opciones similares
sect2 Palabras clave del C++ Estaacutendar
Keyword referencia Keyword referencia Keyword referencia
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
El tratar de la estructura loacutegica de un programa ( 131) se sentildealoacute que tokens son los elementos
en que el preprocesado desmenuza el coacutedigo fuente En un lenguaje de programacioacuten los tokens son el equivalente a las palabras y signos de puntuacioacuten en el lenguaje natural escrito Los tokens
estaacuten separados por elementos de separacioacuten que reciben el nombre geneacuterico de separadores (
14)
Comprenden los siguientes tipos de elementos (podriacuteamos 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 sentildealadas en ( 321)
Identificadores Su nuacutemero puede ser virtualmente infinito dentro de ciertas normas el
programador es libre de elegir los que mejor se ajusten a sus necesidades( 322)
Constantes Existen varias clases cuyos detalles se exponen en las paacuteginas siguientes (
323)
operadores ( 49)
signos de puntuacioacuten tambieacuten llamados puntuadores ( 326)
En ocasiones los operadores y signos de puntuacioacuten comparten la misma representacioacuten
escrita En estos casos el sentido debe deducirse del contexto y por la forma en que estaacuten agrupados los diversos signos
El conjunto de siacutembolos grupos de siacutembolos y palabras utilizados en C++ como operadores yo puntuadores es el siguiente (los operadores se han sentildealado en azul)
[ ] ( )
lt gt lt gt
+ - ^ amp | ~
= lt gt += -= = = =
^= amp= |= ltlt gtgt gtgt= ltlt= == =
lt= gt= ampamp || ++ -- -gt -gt
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 sintaacutectico (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
321 Palabras clave
sect1 Sinopsis
Las palabras clave (Keywords) son identificadores utilizados por el lenguaje para fines
especiales y no pueden ser utilizadas como identificadores (por esta razoacuten se suelen denominar tambieacuten palabras reservadas) Por ejemplo no pueden ser utilizadas como nombres de variables clases o funciones
El primitivo C de Kerningham y Ritchie teniacutea solo 27 el C estaacutendar las amplioacute a 32 y C++ antildeadioacute algunas maacutes Hay que advertir que aunque el Estaacutendar C++ define perfectamente cuales son las palabras reservadas incluidas a continuacioacuten 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 opcioacuten -A de compilacioacuten (
143) que permite forzar las reglas a ANSI C++ estricto con el fin de conseguir un coacutedigo
lo maacutes portable posible Con esta opcioacuten las palabras clave no estrictamente ANSI son ignoradas como tales El resto de compiladores (MS Visual y GCC) tienen opciones similares
sect2 Palabras clave del C++ Estaacutendar
Keyword referencia Keyword referencia Keyword referencia
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Una vez entregado el fuente al compilador es precisamente el analizador sintaacutectico (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
321 Palabras clave
sect1 Sinopsis
Las palabras clave (Keywords) son identificadores utilizados por el lenguaje para fines
especiales y no pueden ser utilizadas como identificadores (por esta razoacuten se suelen denominar tambieacuten palabras reservadas) Por ejemplo no pueden ser utilizadas como nombres de variables clases o funciones
El primitivo C de Kerningham y Ritchie teniacutea solo 27 el C estaacutendar las amplioacute a 32 y C++ antildeadioacute algunas maacutes Hay que advertir que aunque el Estaacutendar C++ define perfectamente cuales son las palabras reservadas incluidas a continuacioacuten 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 opcioacuten -A de compilacioacuten (
143) que permite forzar las reglas a ANSI C++ estricto con el fin de conseguir un coacutedigo
lo maacutes portable posible Con esta opcioacuten las palabras clave no estrictamente ANSI son ignoradas como tales El resto de compiladores (MS Visual y GCC) tienen opciones similares
sect2 Palabras clave del C++ Estaacutendar
Keyword referencia Keyword referencia Keyword referencia
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
asm 410 and 498 and_eq 498
auto 418a bitand 498 bitor 498
bool 321b break 4104 case 4102
catch 16 char 221 class 4112
compl 498 493 const 321c const_cast 499a
continue 4104 default 4102 delete 4921
do 4103 double 221 dynamic_cast 499c
else 4102 enum 323g 47 explicit 4112d1
export 4121b extern 418d 144 false 321b
float 221 for 4103 friend 4112a1
goto 4104 if 4102 inline 446b
int 221 long 223 mutable 418e
namespace 4111 new 4920 not 498
not_eq 498 operator 4918 or 498
or_eq 498 private 4112a protected 4112a
public 4112a register 418b reinterpret_cast 499d
return 447 short 223 signed 223
sizeof 4913 static 418c static_cast 499b
struct 45 switch 4102 template 412
this 4116 throw 16 true 321b
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
try 16 typedef 321a typeid 4914
typename 321e union 46 unsigned 223
using 4111 virtual 4112c1 void 221
volatile 321d 419 wchar_t 221a1 323d while 4103
xor 498 xor_eq 498
En este apartado estudiaremos las palabras clave C++ que por una u otra razoacuten no sean introducidas en ninguacuten otro epiacutegrafe Para distinguirlas del resto a lo largo de esta obra cuando
aparecen fuera del coacutedigo fuente se imprimen en negrita y color negro Por ejemplo int es una
palabra clave
Nota las palabras clave __try y try son una excepcioacuten Dentro del mecanismo de manejo
de excepciones de C++ ( 16) 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
321a typedef
sect1 Sinopsis
La palabra reservada typedef se utiliza para asignar un alias (otro nombre) a un tipo No crea
ninguacuten nuevo tipo solo define un nuevo identificador (type-id 22) para un tipo que ya tiene su
propio identificador (el identificador puede ser un nombre o una expresioacuten compleja que contiene al
nombre) Es importante recalcar que el nuevo nombre es un antildeadido y no sustituye al identificador
original Ambos identificadores pueden ser intercambiados libremente en cualquier expresioacuten
Formalmente typedef es un especificador de identificador (nombre) Su introduccioacuten 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 notacioacuten no es lineal sino que mimetiza la sintaxis de las expresiones que estaacute basada en precedencias En
este sentido la utilizacioacuten de typedef permite paliar en parte el problema mejora la legibilidad y
ayuda a la documentacioacuten y mantenimiento del programa ya que permite sustituir identificadores de tipo complejos por expresiones maacutes sencillas
sect2 Sintaxis
typedef lttipogt ltaliasgt
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Asigna un nombre ltaliasgt con el tipo de dato de lttipogt
Nota para distinguir un identificador ltaliasgt introducido con un typedef de un nombre de
tipo normal lttipogt 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
sect3 Ejemplos
typedef unsigned char BYTE
en lo sucesivo cualquier referencia a BYTE (es una tradicioacuten de CC++ utilizar los alias-typedef en
mayuacutesculas) 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 = 314
KF_PTR ppi = amppi
typedef long clock_t no seriacutea muy C++ mejor CLOCK_T
clock_t slice = clock()
sect31 En realidad el nuevo identificador introducido por typedef se comporta dentro de su aacutembito
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
Tambieacuten pueden encadenarse de forma que pueden definirse nuevos alias en funcioacuten de otros definidos previamente Por ejemplo
typedef char CHAR
typedef CHAR PCHAR LPCH PCH NPSTR LPSTR PSTR
sect32 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 Ameacuterica
PCSTR ptr2 = Hola Ameacuterica
const char ptr3 = Hola Ameacuterica
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
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
sect33 Otros ejemplos de typedef utilizados frecuentemente en la programacioacuten Windows (
Ejemplos)
sect4 Asignaciones complejas
Es uacutetil utilizar typedef para asignaciones complejas en particular en la declaracioacuten y definicioacuten de
punteros a funciones Por ejemplo
typedef long (((FPTR)())[5])() L1
FPTR an L2
La sentencia L1 define un identificador FPTR como un puntero a funcioacuten que no recibe
argumentos y devuelve un puntero a array de 5 punteros a funcioacuten que no reciben ninguacuten
paraacutemetro y devuelven long Despueacutes L2 declara que an es un elemento del tipo indicado
typedef void (new new_handler)() L3
new_handler set_new_handler(new_handler) L4
L3 define new_handler como el identificador de un puntero a funcioacuten que no recibe argumentos
y devuelve void [2] Despueacutes L4 declaraset_new_handler como el nombre de una funcioacuten que
devuelve el tipo new_handler recieacuten definido y acepta un uacutenico argumento de este mismo tipo
typedef void (XPMF)(int) L5
PMF pf = ampXfunc L6
L5 define el identificador PMF como puntero a funcioacuten-miembro de la clase X que recibe un int y
no devuelve nada L6 declara pf como tipo PMF(puntero a funcioacuten) que apunta al
meacutetodo func de X
sect41 Cuando se trata de expresiones muy complejas puede ser uacutetil proceder por fases
aprovechando la propiedad ya enunciada (sect31 ) de que pueden definirse nuevos alias en
funcioacuten de otros definidos previamente Por ejemplo queremos definir un puntero p a matriz de 5
punteros a funcioacuten que toman un entero como argumento y devuelven un puntero a caraacutecter En este caso puede ser conveniente empezar por las funciones
char foo(int) foo es una funcioacuten aceptando int y
devolviendo char
typedef char F(int) F es un alias de funcioacuten aceptando int y devolviendo
a continuacioacuten 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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
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 declaracioacuten del tipo solicitado
M p
Cualquier manipulacioacuten posterior del tipo mencionado resulta ahora mucho maacutes sencilla Por ejemplo la declaracioacuten
int foo(M)
corresponde a una funcioacuten aceptando un puntero a matriz que devuelve un puntero a int
sect42 En ocasiones la simplificacioacuten mencionada el en paacuterrafo anterior permite solventar alguacuten que otro problema con la compilacioacuten de expresiones complejas Por ejemplo un miembro de cierta clase tiene la siguiente declaracioacuten
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
Como sugiere su nombre Garray es una clase geneacuterica destinada a almacenar matrices de
objetos de cualquier tipo estaacute 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 libreriacutea estaacutendar de plantillas STL- tambieacuten
definida en MyNAMESPACE En resumen arrQuer es una matriz de cadenas de caracteres
Ocurre que deseo incluir una invocacioacuten expliacutecita para la destruccioacuten del objeto arrQuer en el
destructor de MYClass Algo como
class MYClass
MyNAMESPACEGarrayltMyNAMESPACEMyStringgt arrQuer
~MYClass()
arrQuer~MyNAMESPACEGarrayltMyNAMESPACEMyStringgt()
Compiler error
Sin embargo el compilador [3] muestra un mensaje de error porque no es capaz de interpretar
correctamente la sentencia sentildealada En este caso la utilizacioacuten de un typedef resuelve el
problema y el compilador construye sin dificultad la aplicacioacuten
class MYClass
typedef MyNAMESPACEGarrayltMyNAMESPACEMyStringgt ZSTR
ZSTR arrQuer
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
~MYClass()
arrQuer~ZSTR() Compilacioacuten Ok
amp5 Tambieacuten 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 definicioacuten de una estructura anoacutenima que puede ser utilizada a traveacutes de su typedef Por supuesto aunque no es usual necesitar el nombre y el alias simultaacuteneamente
tambieacuten 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 definicioacuten real ( 455c)
amp6 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 liacutenea de coacutedigo ( en mi opinioacuten quizaacutes sea esta la razoacuten maacutes
importante para la utilizacioacuten 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 (
224) a pesar de ello utilizamos la expresioacuten
typedef int INT32
en lo sucesivo para todas las referencias utilizamos INT32 en vez de int Por ejemplo
INT32 x y z
Si tuvieacutesemos que portar el coacutedigo a una maacutequina o a un compilador en el que int fuese menor y
por ejemplo los 32 bits exigieran un long int solo tendriacuteamos que cambiar la liacutenea de coacutedigo
del typedef
typedef long INT32 Todas las demaacutes referencias se mantienen
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
INT32 x y z Ok
sect7 No estaacute permitido usar typedef con clases de declaracioacuten adelantada ( 4114) Por ejemplo
seriacutea incorrecto
typedef struct COMPLEX Ilegal
Tampoco estaacute permitido utilizarlo en la definicioacuten 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 despueacutes 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() seriacutean tratadas como funciones normales no como constructor y destructor de la
estructura
sect8 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 ( 4111a)
Typedefs en Windows
sect1 Sinopsis
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Los typedef son de utilizacioacuten muy comuacuten ya que en muchas ocasiones suponen una economiacutea y
simplificacioacuten en la notacioacuten Sin embargo como hemos sentildealado ( 321a) una de las razones
de su uso y quizaacutes la maacutes importante es que permite concentrar en un solo punto del coacutedigo 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 profusioacuten 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 aplicacioacuten 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 seraacute encomendado a los ficheros de
cabecera que pueden contener distintas definiciones de este typedef para cada compilador
concreto
A continuacioacuten se exponen algunos de los identificadores maacutes utilizados en la programacioacuten CC++ para Windows junto con una breve descripcioacuten de sus caracteriacutesticas
WINAPI En realidad no se refiere a un tipo de dato sino a una convencioacuten de llamada a
funcioacuten ( 446a) En las primitivas versiones de Windows este identificador se
referiacutea a la convencioacuten _pascal En las versiones de 32 bits se corresponde con la
convencioacuten estaacutendar de llamada En particular la funcioacuten WinMain que en estas
aplicaciones sustituye a la funcioacuten main del CC++ estaacutendar utiliza esta
convencioacuten
CALLBACK Es otra convencioacuten de llamada En particular para aquellas fuciones de retrollamada (call-back) de la aplicacioacuten que deben ser invocadas por el Sistema Operativo Es el caso de los denominados window procedures y dialog procedures Inicialmente se referiacutean a la convencioacuten FAR PASCAL pero actualmente son llamadas estaacutendar (_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 alfanumeacutericas al estilo
C claacutesico terminadas en el caraacutecter nulo (NTBSs 323f) Definidas
como char FAR [3]
LPCSTR Anaacutelogos 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 tamantildeo depende del entorno (Windows 16 32 o 64
bits) Es sinoacutenimo de unsigned int y generalmente es utilizado en sustitucioacuten 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 paraacutemetros dos de los cuales son de
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
propoacutesito general Este tipo corresponde a uno de ellos
LPARAM Tipo del segundo paraacutemetro de uso general de las funciones call-back
LPVOID Puntero geneacuterico equivalente a void Suele utilizarse con preferencia a LPSTR
En la mayoriacutea de los casos el intercambio de datos entre las aplicaciones Window y la API Sistema se concreta en estructuras (en el sentido C del teacutermino) que se definen mediante los oportunos defines y que se manejan a traveacutes de punteros que aquiacute son conocidos como manejadores (hanles) Muchas funciones de la API tanto de servicios generales como de servicios graacuteficos (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 continuacioacuten se relacionan algunos de los maacutes frecuentes
HANDLE manejador geneacuterico Debe ser sustituido por uno maacutes especiacutefico siempre que sea posible
HINSTANCE handle a instancia de una aplicacioacuten (por ejemplo el programa en ejecucioacuten)
HDC handle a contexto graacutefico DC (device context) Un DC se materializa en una
estructura que define un conjunto de objetos relacionados con la GDI de Windows (objetos graacuteficos) sus atributos y modos que afectan a sus salidas Entre estos objetos estaacuten una pluma pen para trazado de liacuteneas un pincel brush para relleno de aacutereas un mapa de bits bitmap una paleta de colores una referencia al aacuterea canvas en la que se realizaraacuten las operaciones de dibujo y una regioacuten dentro de ella
HMODULE handle a moacutedulo
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 disentildeo graacutefico GDI (Graphic Design Interface)
Excepto metaficheros
HMETAFILE handle a metafichero
Nota las aplicaciones para el SO Windows utilizan dos herramientas para
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
almacenar imaacutegenes 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 informacioacuten graacutefica en un formato independiente de cualquier dispositivo concreto (device-independent format)
HDWP handle a una estructura DeferWindowPos() Esta funcioacuten cambia la estructura que
define la posicioacuten y tamantildeo de una ventana
HACCEL handle a tabla de aceleradores Estas son matrices de estructuras ACCEL que
definen combinaciones de teclas aceleradoras (accelerators keystrokes) de un hilo de ejecucioacuten (thread) Responden a la siguiente definicioacuten 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 diaacutelogo (dialog box) un
botoacuten etc
A continuacioacuten se muestran algunos de estos typedef tomados de los ficheros de cabecera
correspondientes [1] Como puede comprobar algunos estaacuten definidos en funcioacuten de otros en un proceso recursivo aunque el preprocesador las traslada finalmente a su definicioacuten 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 UCHARPUCHAR
typedef wchar_t WCHAR TCHAR OLECHAR
typedef char PSZ
typedef unsigned int PUINT
typedef TCHAR TBYTEPTCHPTBYTE
typedef TCHAR LPTCHPTSTRLPTSTRLPPTCHAR
typedef const TCHAR LPCTSTR
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
typedef void HANDLE
typedef PVOID HANDLE
typedef HANDLE HDWP PHANDLELPHANDLE
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 PVOIDLPVOID
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
321b bool false true
sect1 Sinopsis
La palabra-clave bool declara un tipo especial de variable denominada booleana ( 01) que
solo puede tener dos valores cierto y falso [1]
Nota por razoacuten de los valores que pueden adoptar (ciertofalso) a estas variables tambieacuten se
las denomina variables loacutegicas
sect2 Sintaxis
bool ltidentificadorgt
sect3 Descripcioacuten
Evidentemente el tipo bool estaacute especialmente adaptado a para realizar comprobaciones loacutegicas
de hecho todo el aacutelgebra 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 (numeacutericamente es cero) true tiene el valor cierto (numeacutericamente es uno) Estos
literales booleanos son Rvalues no se les puede hacer una asignacioacuten (no pueden estar a la
izquierda de una asignacioacuten 21)
bool val = false declara val variable Booleana y la inicia
val = true ahora se cambia su valor (nueva asignacioacuten)
true = 0 Error
sect4 Conversioacuten (modelado) de tipos
Tenga en cuenta que los bool y los int son tipos distintos Sin embargo cuando es necesario el
compilador realiza una conversioacuten o modelado automaacutetico ( ) de forma que pueden utilizarse
libremente valores bool (true y false) junto con valores int sin utilizar un modelado expliacutecito Por
ejemplo
int x = 0 y = 5
if (x == false) printf(x falson) Ok
if (y == truee) printf(y cierton) Ok
if ((bool) x == false) printf(x falson) Modelado innecesario
Estas conversiones entre tipos loacutegicos y numeacutericos son simplemente una concesioacuten del C++ para poder aprovechar la gran cantidad de coacutedigo C existente Tradicionalmente en C se haciacutea corresponder falso con el valor cero y cierto con el valor uno (o distinto de cero)
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
El proceso consiste en que en las expresiones aritmeacuteticas y loacutegicas las variables booleanas son convertidas a enteros (int) Las operaciones correspondientes (aritmeacuteticas y loacutegicas) se realizan
con enteros y finalmente el resultado numeacuterico es vuelto a bool seguacuten las reglas de conversioacuten
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 numeacutericas) antes de utilizarlas en
expresiones loacutegicas ( 499) 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 anaacutelogas a las anteriores
Para convertir un Rvalue tipo bool a un Rvalue numeacuterico false cero
true uno
Para convertir tipos aritmeacuteticos (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
sect5 Los tipos bool y los literales false y true se pueden utilizar para realizar comprobaciones
loacutegicas En el ejemplo que sigue se muestra como hacer test booleanos con bool true y false
include ltiostreamgt
using stdcout
using stdendl
bool func() Func devuelve un tipo bool
return NULL NULL es convertido a Booleano (false)
return false esta sentencia es ideacutentica 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 = 101 j es tipo float (no booleano)
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Test para enteros
if (i == true) cout ltlt Cierto el valor es 1 ltlt endl
if (i == false) cout ltlt Falso el valor es 0 ltlt endl
Test para punteros
if ((bool) iptr == false) cout ltlt Puntero no vaacutelido ltlt endl
Para comprobar el valor j se modela a tipo bool
if ((bool) j == true) cout ltlt el Booleano j es cierto ltlt endl
Test de funcioacuten devolviendo Booleano
val = func()
if (val == false)
cout ltlt func() devuelve falso
if (val == true)
cout ltlt func() devuelve cierto
return false false es convertido a 0 (int)
Salida del programa
Cierto el valor es 1
Puntero no vaacutelido
el Booleano j es cierto
func() devuelve falso
sect6 El lenguaje C++ tiene operadores y sentencias en las que se exige la presencia de un
tipo bool son las siguientes
Operadores loacutegicos ( 498) AND (ampamp) OR (||) NOT () Producen un
resultado booleano y sus operandos son tambieacuten valores loacutegicos o asimilables a ellos (los
valores numeacutericos son asimilados a true o false seguacuten su valor)
Operadores relacionales ( 4912) lt gt lt= gt= Aceptan diversos tipos de operando
pero el resultado es de tipo booleano
Expresioacuten condicional en las sentencias if ( 4102) y en las
iteraciones for while y dowhile ( 4103) En todos estos casos la sentencia
condicional produce un bool como resultado
El primer operando del operador ( 496) es convertido a bool
321c const
sect1 Sinopsis
La palabra clave const se utiliza para hacer que un objeto-dato sentildealado 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 ideacutenticas propiedades
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
que el original pero que no puede ser cambiado despueacutes de su inicializacioacuten (se trata pues de un
verdadero especificador de tipo)
Cuando se utiliza en la definicioacuten de paraacutemetros de funciones o con miembros de clases
tiene significados adicionales especiales
sect2 Sintaxis
Existen cuatro formas posibles
const [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ] sect21
ltnombre-de-funcioacutengt ( const lttipogtltnombre-de-variablegt ) sect22
ltnombre-de-metodogt const sect23
const ltinstanciado de clasegt sect24
Nota observe que no consideramos aquiacute la forma
const [lttipo-de-variablegt] ltnombre-de-funcioacutengt ()
Significariacutea una funcioacuten devolviendo un tipo constante
Como el lector puede suponer la pluralidad de formas sintaacutecticas permitidas trasluce la variedad de significados que dependiendo de las circunstancias puede asumir esta palabra clave Esta variedad se traduce en un comportamiento camaleoacutenico que cuesta trabajo asimilar en toda su extensioacuten Maacutexime si se le suma el hecho de que su comportamiento puede ser afectado por ciertos especificadores adicionales
sect3 Descripcioacuten
La palabra clave const declara que un valor no es modificable por el programa Puesto que no
puede hacerse ninguna asignacioacuten posterior a un identificador especificado como const esta debe
hacerse inevitablemente en el momento de la declaracioacuten a menos que se trate de una
declaracioacuten extern ( 418d)
Ejemplos
const float pi = 314 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
sect4 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 praacutecticas como veremos ( 421a) un puntero-a-constante-tipoX no es
intercambiable por un puntero-a-tipoX
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
sect5 Cuando no se indica lttipo-de-variablegt en ausencia de otro especificador const por siacute
misma equivale a int
const ptr Puntero a int constante cons x = 10 Entero constante
sect6 Un caraacutecter entre comillas simples es un caraacutecter constante const char (declaracioacuten impliacutecita)
y puede ser asignado a una variable o utilizado en cualquier lugar que un char normal
const char letra_a = a
sect7 Cualquier futuro intento de asignacioacuten a una constante origina un error de compilacioacuten (aunque
el resultado exacto depende de la implementacioacuten) por lo que seguacuten las declaraciones
anteriores las que siguen son ilegales
pi = 30 NO Asigna un valor a una constante
i = peso++ NO Incrementa una constante
pt1 = Marte NO Apunta pt1 a otra entidad
sect8 const y volatile
Aunque en principio pueda parecer un contrasentido el especificador const puede coexistir con el
atributo volatile ( 321d) Por tanto es vaacutelida la expresioacuten
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
sect9 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 = ampx Ok
cons int y = 10
int yptr = ampy L4 Error
const int yptr = ampy Ok
Observe que const-tipoX no puede ser asignado a tipoX que es el error que se produce en L4
En este caso el compilador lo expresa Cannot convert const int to int
sin embargo la inversa siacute es posible es decir tipoX puede ser asignado a const-tipoX
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
int y = 10
const int yptr = ampy Ok
Tenga en cuenta que un puntero declarado como constante no puede ser modificado pero el
objeto al que sentildeala siacute que puede modificarse (de hecho el objeto sentildealado no tiene porqueacute ser constante) Siguiendo con las definiciones anteriores puede hacerse
char const pt1 = Sol pt1 puntero constante-a-char
char pt3 = pt1 el puntero pt3 sentildeala a la cadena Sol
pt3++ el puntero pt3 sentildeala a la cadena ol
pt3 = a modifica segundo caraacutecter de Sol
cout ltlt pt1 -gt Sal
Nota en determinados casos una constante puede ser indirectamente modificada a traveacutes de un puntero aunque no sea aconsejable y el resultado dependa de la implementacioacuten Ver una discusioacuten mas detallada sobre este asunto de punteros y constantes Puntero constantea
constante ( 421e)
sect10 El atributo const puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast) se trata de una especie
de casting especiacutefico de la propiedad const aunque con ciertas limitaciones
sect11 const en paraacutemetros de funciones
El especificador const puede ser utilizado en la definicioacuten de paraacutemetros de funciones Esto
resulta de especial utilidad en tres casos en los tres el fin que se persigue es el mismo indicar que
la funcioacuten no podraacute cambiar dichos argumentos (segundo caso de la sintaxis )
Con paraacutemetros de funciones que sean de tipo matriz (que se pasan por referencia) Ejemplo
int strlen(const char[])
Cuando los paraacutemetros son punteros (a fin de que desde dentro de la funcioacuten no puedan ser modificados los objetos referenciados) Ejemplo
int printf (const char format )
Cuando el argumento de la funcioacuten sea una referencia previniendo asiacute que la funcioacuten pueda modificar el valor referenciado Ejemplo
int dimen(const X ampx2)
En los tres casos sentildealados la declaracioacuten de los paraacutemetros como const garantiza que las
respectivas funciones no puedan modificar el contenido de los argumentos
sect12 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) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Utilizado en el sentido tradicional (objeto-dato que no puede ser modificado) sect121
Aplicado a meacutetodos de clase (con un sentido muy especial) sect122
Aplicado a objetos (instancias de clase) asignaacutendoles ciertas caracteriacutesticas sect123
sect121 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 Camp c2) declara argumento c2 constante (segundo caso de sintaxis)
c1x = 3 Ok objeto c1 modificable
c1k = 4 Error Miembro k no modificable
c2x = 5 Error objeto c2 NO modificable return (x + k + c1x + c2k)
Nota puesto que en el cuerpo de la clase no pueden hacerse asignaciones C++ proporciona
un meacutetodo especial para inicializar estas constantes (caso de k) ( 4112d3)
sect122 Aplicado a meacutetodos de clase
Tercer caso de la sintaxis
ltnombre-de-funcioacutengt const
Si se utiliza el especificador const en la declaracioacuten de un meacutetodo de clase la funcioacuten 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 coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Al compilar este coacutedigo se produce un error Cannot modify a const object in function
Cfunc(int) const avisaacutendonos que la funcioacuten func declarada constante no puede
modificar el valor de la variable x (ni ninguacuten otro miembro de C sea o no constante)
Noacutetese que si la definicioacuten de la funcioacuten estaacute fuera de la definicioacuten de la clase tambieacuten es necesario el especificador En el ejemplo anterior
class C
int x
int func(int) const
inline int Cfunc(int i) const
Tenga en cuenta que en estos casos el especificador const forma parte del tipo de la funcioacuten
miembro de forma que
class C
int x
int func(int)
inline int Cfunc(int i) const
Produce un error de compilacioacuten Cfunc(int) const is not a member of C
Observe que el especificador const puede aparecer simultaacuteneamente en tres posiciones distintas
de la declaracioacuten de un meacutetodo
struct C
int x
const intamp foo (const intamp) const
const intamp Cfoo(const intamp i) const cout ltlt xxx ltlt x i ltlt endl
return this-gtx
void func()
C c1 = 3
int x = 3
foo(x) -gt xxx 30
El primero significa que el valor devuelto por la funcioacuten no podraacute ser utilizado para modificar el objeto original El segundo indica que el argumento recibido por la funcioacuten no podraacute ser modificado
en el cuerpo de esta El tercero sentildeala que el meacutetodo Cfoo no podraacute ser utilizado para modificar
ninguacuten miembro de la estructura C a la que pertenece
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
sect123 Aplicado a instancias de clases
Ademaacutes del sentido estricto de constante cuando se utiliza con miembros de clases const es una
caracteriacutestica antildeadida 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 tambieacuten esteacuten definidos como const de
forma que si un objeto-const invoca un meacutetodo no-const el compilador muestra un mensaje de
alerta avisando que un objeto-const estaacute utilizando un miembro no-const
Ejemplo
include ltiostreamhgt
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 ltlt Funcion no-modificativa ltlt endl
return i++
int func(int i) versioacuten no-const de func
cout ltlt Modifica datos privados ltlt endl
return num = i modifica miembro num
int f(int i) funcioacuten no-const
cout ltlt Funcion no-modificativa llamada con ltlt i ltlt endl
return i
int main() ======================================
C c_nc Instancia-1 Utilizaraacute miembros no-const
const C c_c Instancia-2 Utilizaraacute miembros const
cuarto caso de la sintaxis
c_ncfunc(1) invoca versioacuten no-const de func
c_ncf(1) Ok f es funcioacuten no-const
c_cfunc(1) invoca versioacuten cons de func
c_cf(1) Aviso objeto-const invoca funcioacuten 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 funcioacuten func No se trata de un caso de
polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
especificador const en una de ellas el compilador hubiese dado un error Multiple declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se
utilizaraacute en cada invocacioacuten 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 invocacioacutenc_ncfunc(1) utiliza la versioacuten no-const mientras
que la invocacioacuten c_cfunc(1) utiliza la versioacuten constante
Puede comprobarse tambieacuten que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-const function Cf(int) called for const object in function main() avisando que una funcioacuten no-constante (f) ha sido invocada por un objeto constante
(c_c)
Nota hay forma de saltarse esta restriccioacuten ver mutable ( 418e)
Temas relacionados
Constantes ( 323) Todo lo referente a los diversos tipos de constantes y su
declaracioacuten
Cosntantes literales ( 323f) Un tipo especial de matrices de caracteres
Enumeradores ( 323g) Un tipo especial de variable cuyo rango es una serie de constantes enteras
321d volatile
sect1 Sinopsis
Hemos sentildealado repetidas veces que una de las premisas de disentildeo del C++ es la velocidad de ejecucioacuten En este sentido los disentildeadores de estos compiladores adoptan todas las estrategias posibles para garantizarlo Por ejemplo consideremos el siguiente trozo de coacutedigo
func ( ) realiza determinado proceso
int limit = 1200 definicioacuten del liacutemite para el bucle
for (int c=0 cltlimit c++) func( )
El proceso definido por func se repite mientras que el contador c se mantiene inferior al
liacutemite limit definido en la sentencia anterior Puesto que en la condicioacuten del for ( 4103) no se
altera el valor de la variable limit el compilador puede asumir que este valor se mantiene
constante durante la ejecucioacuten del bucle y puede que sea almacenado como variable de registro (
418b) a fin de ahorrarse lecturas y tenerla raacutepidamente accesible para la
comparacioacuten cltlimit es maacutes que posible que c tambieacuten sea declarada variable de registro en
cuyo caso las operaciones de incremento unitario c++ y comparacioacuten con limit seriacutean procesos
muy raacutepidos
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
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
estaacute controlando un sistema de instrumentacioacuten en el que la variable limit puede ser alterada por
un dispositivo o proceso externo (puede ser otro hilo de ejecucioacuten del programa - 17-)
En tales casos nos encontramos en una situacioacuten justamente opuesta a las constantes (
321c) En aquel caso se indica al compilador Este valor se mantendraacute inalterable a lo largo de la ejecucioacuten En ocasiones como la descrita necesitamos indicar al compilador justamente lo contrario No hacer ninguna suposicioacuten sobre este valor incluso si se ha leiacutedo en la sentencia anterior
Para conseguir esto C++ dispone de un indicador especiacutefico la palabra clave volatile es un modificador que antildeadido a una variable advierte al compilador que esta puede ser modificada por una rutina en segundo plano (background) por una rutina de interrupcioacuten o por un dispositivo de entrada salida Es decir que puede sufrir modificaciones fuera del control del programa
La declaracioacuten de un objeto con este atributo previene al compilador de hacer ninguna asuncioacuten sobre el valor del objeto mientras se ejecutan instrucciones en las que esteacute involucrado advirtieacutendolo que dicho valor puede cambiar en cualquier momento Tambieacuten previene al compilador de que no debe hacer de dicho objeto una variable de registro
sect2 Sintaxis
volatile [lttipo-de-variablegt] ltnombre-de-variablegt [ = ltvalorgt ]
ltnombre-de-funcioacutengt ( volatile lttipogt ltnombre-de-variablegt )
ltnombre-de-metodogt volatile
volatile ltinstanciado de clasegt
sect3 Ejemplo
volatile int ticks primer caso de la sintaxis
void timer( ) ticks++
void wait (int interval)
ticks = 0
while (ticks lt 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 estaacute asociado a un dispositivo hardware de
interrupciones) Un compilador correctamente optimizado no deberiacutea cargar la
variable ticks dentro de la rutina de comprobacioacuten del bucle while dado que el bucle no cambia
el valor de dicha variable
Otros ejemplos 493 91
sect4 volatile y const
Como se ha sentildealado el especificador const puede coexistir con el atributo volatile ( 321c)
sect5 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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
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 = ampx Error
const int xptr = ampx Ok
volatile int y = 10
int yptr = ampy Error
volatile int yptr = ampy Ok
int z
volatile int zptr = ampz Error
sect6 volatile con miembros de clases
El atributo volatile puede ser utilizado con miembros de clases (propiedades y meacutetodos) de forma
parecida al modificador const con miembros de clase ( 321c) En efecto puede ser utilizado de tres formas distintas
sect61 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 + Cx
sect62 Cuando se aplica a meacutetodos de clase (tercer caso de la sintaxis) Ejemplo
ltnombre-de-metodogt volatile
Si en la declaracioacuten de un meacutetodo de clase se utiliza volatile la funcioacuten debe ser invocada por objetos tambieacuten 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
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
class C
int x Private por defecto
int func(int i) volatile declara func volatile
x = x + i
sect63 Cuando se aplica a instancias de clase
Ademaacutes del sentido estricto (variable que puede ser modificada desde fuera del programa) cuando se utiliza con miembros de clases volatile es una caracteriacutestica antildeadida de seguridad En efecto los objetos volatile intentan usar las funciones miembro definidas a su vez como volatile Si un objeto volatile invoca una funcioacuten miembro no-volatile el compilador muestra un mensaje avisando de la circunstancia
Ejemplo
include ltiostreamhgt
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 ltlt Funcion volatile ltlt endl
return num = i modifica miembro no-volatile
int func(int i) versioacuten no-volatile de func
cout ltlt Funcion no-volatile ltlt endl
return num = i modifica miembro no-volatile
void f(int i) funcioacuten no-volatile
cout ltlt Funcion no-volatile llamada con ltlt i ltlt endl
int main() =================================
C c_nv Instancia-1 Utilizaraacute funciones no-
volatiles
volatile C c_v Instancia-2 Utilizaraacute funciones
volatiles
cuarto caso de la sintaxis
c_nvfunc(1) invoca versioacuten no-volatil de func
c_nvf(1) Ok f es funcioacuten no-volatil
c_vfunc(1) invoca versioacuten volatil de func
c_vf(2) Aviso objeto-volatil invoca funcioacuten 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 funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Funcion volatile
Funcion no-volatile llamada con 2
Observe que la clase C tiene dos versiones de la misma funcioacuten func y que no se trata de un
caso de polimorfismo puesto que ambas tienen exactamente la misma definicioacuten En ausencia del
especificador volatile en una de ellas el compilador hubiese dado un error Multiple
declaration for Cfunc(int) pero la presencia de este modificador hace que el
compilador considere que ambos meacutetodos son distintos La distincioacuten de cual de las dos se utilizaraacute en cada invocacioacuten 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 invocacioacutenc_nvfunc(1) utiliza la versioacuten no-volatile
mientras que la invocacioacuten c_vfunc(1) utiliza la versioacuten volatile
Tambieacuten puede comprobarse que el compilador genera un mensaje de aviso en la penuacuteltima
liacutenea Non-volatile function Cf(int) called for volatile object in
function main() avisando que una funcioacuten no-volaacutetil (f) ha sido invocada por un objeto volaacutetil
(c_v)
sect7 El atributo volatile puede ser reversible C++ dispone de un operador especiacutefico que puede
poner o quitar este atributo de un objeto ( 499aoperador const_cast)
321e typename
sect1 Sinopsis
La palabra clave typename es un especificador de tipo Indica justamente eso que el identificador
que la acompantildea es un tipo (aunque no se haya definido todaviacutea) Una especie de declaracioacuten adelantada para que el compilador no lo rechace (al identificador) y lo tome como tal
sect2 Sintaxis
Son posibles dos formas
typename identificador sect2a
template lt typename identificador gt identificador-de-clase sect2b
sect3 Comentario
La forma sect2a se utiliza para declarar variables que no han sido definidas todaviacutea 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 ( TA ) que no ha sido
definida todaviacutea
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
template ltclass Tgt clase T no definida auacuten
void f()
typedef typename TA TA L3 declara TA como tipo TA
TA a1 L4 declara a1 como de tipo TA
typename TA a2 declara a2 como de tipo TA
TA ptra declara ptra como puntero-a-TA
L3 especifica que cada ocurrencia de TA seraacute sustituida por typename TA lo que significa que
por ejemplo la sentencia L4 es vista por el compilador como typename TA a1
La sintaxis sect2b se utiliza en sustitucioacuten de la palabra clave class en las declaraciones de plantillas
( 4122) El sentido es el mismo significa este argumento es cualquier tipo En el siguiente
ejemplo se utiliza esta sintaxis en la declaracioacuten de dos funciones geneacutericas
template lttypename T1 typename T2gt T2 convert (T1 t1) L1
return (T2)t1
template lttypename X class Ygt bool isequal (X x Y y) L5
if (x==y)return 1 return 0
Observe que la definicioacuten L1 utiliza typename en sustitucioacuten del especificador class mientras
que en L5 se utilizan indistintamente
322 Identificadores
sect1 Sinopsis
Recordemos ( 121) que un identificador es un conjunto de caracteres alfanumeacutericos 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 nuacutemeros Cada lenguaje tiene sus propias reglas que definen como pueden estar construidos En el caso de C++ son las que se indican a continuacioacuten 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 funcioacuten miembro de clase instancia de clase enumerador plantilla o espacio de nombres del programa
sect2 Identificadores C++
Los identificadores C++ pueden contener las letras a a z y A a Z el guioacuten bajo _
(Underscore) y los diacutegitos 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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
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
_
Diacutegitos permitidos 0 1 2 3 4 5 6 7 8 9
Solo hay dos restricciones en cuanto a la composicioacuten
El primer caraacutecter debe ser una letra o el guioacuten bajo El Estaacutendar establece que los identificadores comenzando con guioacuten bajo y mayuacutescula no deben ser utilizados Este tipo de nombres se reserva para los compiladores y las Libreriacuteas Estaacutendar Tampoco se permite la utilizacioacuten de nombres que contengan dos guiones bajos seguidos
El estaacutendar ANSI establece que como miacutenimo seraacuten significativos los 31 primeros caracteres aunque pueden ser maacutes seguacuten la implementacioacuten [1] Es decir para que un compilador se adhiera al estaacutendar ANSI debe considerar como significativos al menos los 31 primeros caracteres
Nota veremos que los identificadores de los operadores ( 49) son un caso especial que se
aparta de estas reglas
Los identificadores distinguen mayuacutesculas y minuacutesculas asiacute que Sum sum y suM son distintos
para el compilador Sin embargo C++Builder ofrece la opcioacuten de suspender la sensibilidad a mayuacutesculas minuacutesculas lo que permite la compatibilidad con lenguajes insensibles a esta
cuestioacuten en este caso las variables globales Sum sum y suM seriacutean consideradas ideacutenticas
aunque podriacutea resultar un mensaje de aviso Duplicate symbol durante el enlazado
sect21 Con los identificadores del tipo __pascal hay una excepcioacuten a esta regla ya que son
convertidos siempre a mayuacutesculas con vistas al enlazado
Los identificadores globales importados desde otros moacutedulos siguen las mismas reglas que los identificadores normales
sect3 Aunque los nombres de los identificadores pueden ser arbitrarios (dentro de las reglas
sentildealadas) se produce un error si se utiliza el mismo identificador dentro del mismo aacutembito
compartiendo el mismo espacio de nombres ( 4111) Los nombres duplicados son legales en
diferentes espacios de nombres con independencia de las reglas de aacutembito
Un identificador no puede coincidir con una palabra clave ( 321) o con el de ninguna
funcioacuten de biblioteca
sect4 El estaacutendar ANSI distingue dos tipos de identificadores
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Identificadores internos los nombres de macros de preprocesado y todas las que no tengan enlazado externo El estaacutendar establece que seraacuten significativos al menos los primeros 31 caracteres
Identificadores externos los que corresponden a elementos que tengan enlazado externo En este caso el estaacutendar es maacutes permisivo Se acepta que el compilador identifique solo seis caracteres significativos y pueda ignorar la distincioacuten
mayuacutesculasminuacutesculas (Enlazado 144)
sect5 Reglas de estilo
Es bastante frecuente que en la ensentildeanza de C++ (y de cualquier otro lenguaje de programacioacuten) no se subraye suficientemente la importancia de la eleccioacuten de los identificadores En este sentido los textos se suelen limitar a sentildealar las reglas formales que impone el lenguaje para la declaracioacuten de nombres Sin embargo como todos los que tienen que ver con la legibilidad del coacutedigo el asunto es de capital importancia Sobre todo si se trata de algo maacutes que del consabido programita Hola mundo y desde luego resulta criacutetico en proyectos medianamente grandes en los que puedan trabajar maacutes de un programador yo deba ser mantenido por personas distintas de su creador original (lo que antes o despueacutes acaba ocurriendo en la informaacutetica 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 minuacutesculas para los nombres de variables y funciones (1) (con frecuencia se utilizan combinaciones
minuacutesculasMayuacutesculas - por ejemplo getRvalue o rColor- aunque la inicial suele ser
minuacutescula) Los identificadores de variables automaacuteticas lo maacutes cortos posibles (2) los de estaacuteticas y globales maacutes largos y descriptivos (3) Los nombres de constantes simboacutelicas normalmente en mayuacutesculas (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 maniacuteas o haacutebitos particulares que pueda tener cada programador la mayoriacutea 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 maacutexima homogeneidad posible en el coacutedigo lo que a la postre redunda en una mayor legibilidad y facilidad de mantenimiento En este sentido cabriacutea sentildealar que dentro de ciertos liacutemites 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 programacioacuten CC++ para las plataformas Windows suelen seguirse determinadas convenciones conocidas
como Notacioacuten Huacutengara [5] en la que el identificador de cada variable comienza con una o varias
letras (minuacutesculas) que sentildealan el tipo de la variable Por ejemplo nValor
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Los nombres de clases se preceden siempre con una C mayuacutescula y la siguiente letra tambieacuten
es mayuacutescula Por ejemplo CAboutDlgCAprenderApp CMainFrame etc Los nombres de
variables comienzan por letras fijas seguacuten 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 mayuacutescula pero la siguiente letra es minuacutescula [6] Por
ejemplo DoDataExchange()InitInstance() OnAppAbout() etc
Este tipo de notacioacuten presenta la ventaja de con un poco de praacutectica es mucha la informacioacuten que puede extraerse de la simple lectura del coacutedigo
En el cuadro adjunto se incluyen algunas de estas convenciones
Prefijo Tipo de datosituacioacuten Ejemplo
a Matriz (array) aValor aX aY
b BOOL (long) bValor bA bB
by BYTE (unsigned char) byValr byA byB
c ch caraacutecter (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
Funcioacuten normal (los meacutetodos 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 alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
p Puntero pValor pA pB
s Cadena alfanumeacuterica (string) sValor sA sB
sz Cadena alfanumeacuterica terminada en
caraacutecter nulo
al viejo estilo C ( 434)
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 ( 411) la letra siguiente
tambieacuten mayuacutescula CDialog CEditView CButton
Nota la programacioacuten Windows utiliza sus propios tipos definidos mediante typedefs (
321a) Generalmente son identificadores expresados en mayuacutesculas ( Ejemplos)
323 Constantes
sect1 Sinopsis
La palabra constante tiene en C++ dos connotaciones sutilmente diferentes aunque relacionadas
que conviene distinguir
sect11 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 coacutedigo del programa y no pueden ser modificados maacutes tarde en tiempo de ejecucioacuten (lo que significa que sus valores deben ser resueltos en tiempo de compilacioacuten) 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 vaacutelidas para conseguir la mayor eficiencia en tiempo de ejecucioacuten
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 ejecucioacuten
sect12 La segunda connotacioacuten es la de tipo ( 21) 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
caraacutecter Asiacute pues distinguimos entre un tipo char y un tipo const char Como praacutecticamente
todos los tipos de objeto-dato posibles en C++ puede declararse constantes existe un universo de tipos C++ simeacutetrico 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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
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 maacutes que un entero al que no se le puede cambiar su valor
sect2 Lo que hace el compilador con los objetos declarados inicialmente como constantes depende de la implementacioacuten Esto significa que no estaacute garantizado que tales objetos tengan un Lvalue (
215) Por ejemplo en const int x = 5 no estaacute 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 cuestioacuten)
Puede ocurrir que por razones de eficacia sea simplemente una especie de define [1] Una especie de nemoacutenico que hace que el compilador lo sustituya por un 5 en cada trozo de coacutedigo
donde aparezca x Incluso en sitios donde aparezca asociada a otras constantes puede estar
resuelto el valor en tiempo de compilacioacuten Por ejemplo si en otro sitio del programa
aparece const int z = 7 y maacutes tarde int w = x + z + ypuede ocurrir que el
compilador establezca directamente int w = 12 + y
Por esta razoacuten no estaacute garantizado que el operador const_cast ( 499a) funcione con objetos
declarados inicialmente como constantes
sect3 Como se ha indicado en C++ existen tantos tipos de constantes como tipos de variables pero
aparte de las ya mencionadas constantes manifiestas ( 141a) solo nos detendremos en las
que por una u otra razoacuten hay cosas interesantes que puntualizar Son las siguientes
Expresiones Constantes ( 323a)
Constantes enteras ( 323b)
Constantes fraccionarias ( 323c)
Constantes caraacutecter de varios subtipos incluyendo elementos aislados y cadenas (
323d 333h 323f)
Enumeraciones ( 323g)
El Estaacutendar C++ denomina literales a lo que el Estaacutendar C denomina constantes y establece que existen 5 tipos de estos literales
Constantes enteras (Integer literal)
Constantes caraacutecter (Character literal)
Constantes fraccionarias (Floating literal)
Constantes de cadena (String literal)
Constantes loacutegicas (Boolean literal)
sect4 Por la forma en que estaacuten expresadas en el coacutedigo pueden considerarse en dos grupos
Directas si estaacuten directamente expresadas Por ejemplo
const float pi = 314159
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
Expresiones ( 323a) si su valor estaacute impliacutecito en una expresioacuten Por ejemplo
const float k = pi 2
sect5 El tipo de dato correspondiente a una constante es deducido por el compilador en base a indicios impliacutecitos como el valor numeacuterico y formato usados en el fuente En algunos casos
tambieacuten por ciertos calificadores expliacutecitos C++ tiene una palabra especiacutefica para este fin const (
321c)
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 KampR cuando se queriacutea utilizar una constante
habiacutea que utilizar un define ( 4910b) en la forma
define PI = 313159
define G = 980665
Etc
323a Expresiones constantes
sect1 Sinopsis
Una expresioacuten constante es aquella que solo implica a constantes (queda reducida a una
constante) por lo que puede ser evaluada en tiempo de compilacioacuten y debe evaluarse a un valor que esteacute en el rango de valores admitidos para el tipo que se declara Por ejemplo si estamos
declarando una constante tipo int la expresioacuten debe reducirse a un int
int const peso = 50 + 20
Los operandos de las expresiones constantes pueden ser constantes enteras ( 323b)
constantes caraacutecter ( 323d) constantes fraccionarias ( 323c) constantes de enumeracioacuten (
323g) expresiones sizeof ( 4913) expresiones de modelado de tipos ( 499) e incluso
otras expresiones constantes aunque en ciertos casos se imponen algunas restricciones
Las expresiones constantes se evaluacutean como el resto de las expresiones con variables y pueden utilizarse en cualquier caso en que sea legal el uso de una constante
sect2 Sintaxis
expresion-constante
Expresion-condicional
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
sect3 Ejemplo
define LEAP 1 en antildeos bisiestos
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31]
sect4 Las expresiones constantes no pueden contener ninguno de los operadores indicados a
continuacioacuten a menos que los operadores esteacuten contenidos dentro del operando de un
operador sizeof ( 4913)
Asignacioacuten int const k = 2+(kte = 4) Error
Coma int const k = (i=1 3) Error
Decremento int const k = kte-- Error
Llamada a funcioacuten int const k = func(4) Error
Incremento int const k = kte++ Error
sect5 Existen muacuteltiples 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 tamantildeo del
campo de bits de una estructura ( 459) el valor de una constante de enumeracioacuten (
323g) el tamantildeo de una matriz ( 431) o el valor de una constante case ( 4102)
sect6 Expresiones constantes restringidas
Las expresiones constantes utilizadas en las directivas de preproceso ( 4910d) estaacuten 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 enumeracioacuten ni expresiones de
modelado de tipo
323b Constantes enteras
sect1 Sinopsis
Las constantes enteras representan un int y pueden estar expresadas en los sistemas de
numeracioacuten decimal octal o hexadecimal En ausencia de ninguacuten sufijo el tipo de
una constante entera se deduce de su valor seguacuten se muestra en las tablas que siguen Observe que las reglas para las constantes decimales son distintas del resto
sect2 Decimal
Se permiten constantes enteras en formato decimal (base 10 224b) dentro del rango 0 a
4294967295 las que excedan este liacutemite seraacuten truncadas Observe que las constantes decimales no pueden comenzar con cero porque seriacutean 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 funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
int i = 0 decimal 0 = octal 0
Tipos adoptados por las constantes decimales en funcioacuten del valor declarado (en ausencia de
sufijos L o U)
0 a 32767 int
32768 a 2147483647 long
2147483648 a 4294967295 unsigned long
gt4294967295 truncado
sect3 Octal
Todas las constantes que empiecen por cero se suponen en octal (base 8 224b) Si una
constante de este tipo contiene diacutegitos ilegales (8 o 9) se produce un mensaje de error como se indica en la tabla adjunta las que exceden del valor maacuteximo 037777777777 son truncadas
Tipos adoptados por las constantes Octales en funcioacuten 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
gt 037777777777 truncado
sect4 Hexadecimal
Cualquier constante que comience por 0x o 0X es considerada hexadecimal [1] base 16 (
224b) despueacutes se pueden incluir los diacutegitos vaacutelidos (09 af AF) Como se indica e el
cuadro adjunto las que excedan del valor maacuteximo 0xFFFFFFFF son truncadas
Tipos adoptados por las constantes hexadecimales en funcioacuten 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
gt0xFFFFFFFF truncado
Ejemplo
long lg1 = 0xFFFF lg2 = 0xFF
cout ltlt lg1 ltlt endl -gt 65535
cout ltlt lg2 ltlt endl -gt 255
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
define CS_VREDRAW 0x0001
define CS_HREDRAW 0x0002
sect5 Sufijos long (L) y unsigned (U)
La adicioacuten de sufijos en la definicioacuten de una constante puede forzar que esta sea de un tipo especiacutefico asiacute 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 grafiacutea (ul
lu Ul lU uL Lu LU o UL)
Los sufijos L l despueacutes 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 seraacute considerada unsigned long si el valor del
nuacutemero es mayor que el decimal 65535 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
sentildealan 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 representacioacuten de constantes
enteras en cualquiera de los tres sistemas de numeracioacuten (en C++Builder)
Nota algunos compiladores utilizan los sufijos llLL y ullULL para referirse a los enteros
extendidos ( 323d) long long y unsigned long long respectivamente
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
323c Constantes fraccionarias
sect1 Sinopsis
Las constantes fraccionarias (tambieacuten llamada de punto flotante) corresponden al concepto matemaacutetico de nuacutemeros fraccionarios Es decir cantidades con cierto nuacutemero de cifras decimales Su representacioacuten el coacutedigo fuente puede contener
Parte entera 37092e-2L
Punto decimal [1] 37092e-2L
Parte fraccionaria 37092e-2L
eE y un entero con signo (exponente) 37092e-2L
Sufijo (indicador de tipo) fF oacute lL 37092e-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 precedieacutendolas con el operador unitario menos ( - )
sect2 Dos posibles notaciones
Las reglas anteriores permiten utilizar para las constantes fraccionarias dos tipos de notacioacuten
Notacioacuten convencional (de punto decimal)
Notacioacuten cientiacutefica (con exponente Ee)
Ejemplos
Expresioacuten Valor 2345e6 2345 10^6 0 0 0 00 1 10 -123 -123 2e-5 20 10^-5 3E+10 30 10^10 09E34 009 10^34
Nota la notacioacuten 10^-5 significa 10 elevado a menos 5 ( 10-5
)
Maacutes informacioacuten sobre la notacioacuten cientiacutefica en ( 224a)
sect3 En ausencia de cualquier sufijo las constantes fraccionarias se consideran de
tipo double aunque se puede obligar a que sea considerada de tipo float antildeadieacutendole el
sufijo f oacute F
Ejemplo
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
x = 1 L1
y = 1f L2
En L1 la constante 10 es considerada double y podriacutea producir una advertencia del
compilador Warning Initializacioacuten to int from double
L2 produciriacutea Warning Initializacioacuten to int from float La razoacuten es que por
tradicioacuten del C en ausencia de una declaracioacuten expliacutecita de tipo en expresiones como L1 y L2 el
compilador C++ supone que x e y son tipo int
Ejemplo relacionado ( 224a)
sect4 De forma anaacuteloga el sufijo l L la fuerza a ser del tipo long double
Ejemplo
long lg1 = 30 L1
long lg2 = 32L L2
long double = 40L L3 Ok
En L1el compilador puede mostrar un aviso Warning initialization to long int from double En L2 el aviso seriacuteaWarning initialization to long int from
long double
sect5 La tabla adjunta muestra los rangos permitidos para los tres tipos
disponibles float double y long double
Tipo Tamantildeo (bits) Rango
float 32 34 10^-38 a 34 10^38
double 64 17 10^-308 a 17 10^308
long double 80 34 10^-4932 a 11 10^4932
323d Constantes caraacutecter
sect1 Sinopsis
Una constante caraacutecter es uno o maacutes caracteres delimitados por comillas simples como A +
o n En C++ son de un tipo especiacutefico 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
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423
sect2 Los tres tipos char
Las constantes de un caraacutecter 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 maacutes alto es puesto a -1 (
= 0xFF) es decir las constantes caraacutecter cuyo valor ASCII es mayor de 127 se representan como nuacutemeros negativos aunque esto puede ser desactivado declarando que los caracteres
son unsigned por defecto
Cualquiera de los tres tipos caraacutecter char signed char y unsigned char se almacenan en 8-bits
(un byte) [2]
En los programas a C++ una funcioacuten 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 vaacutelidos 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 podriacutea aceptar cualquiera de los tres tipos caraacutecter Por ejemplo el coacutedigo que sigue seriacutea aceptable (se produciriacutea una conversioacuten automaacutetica de tipo al pasar el argumento a la funcioacuten)
void func(unsigned char ch)
void main(void)
signed char ch = x
func(ch)
sect3 Constantes de caraacutecter-ancho
El tipo de caracteres ancho se utiliza para representar juegos de caracteres que no caben en el
espacio (1 byte) proporcionado por los caraacutecter normales (char signed char o unsigned char)
Nota histoacuterica en C claacutesico un caraacutecter ancho ocupa dos bytes y cualquier constante caraacutecter
precedida por L es un caraacutecter ancho un tipo de dato denominado wchar_t que en realidad es
un typedef definido en ltstddefhgt
En Borland C++ wchar_t estaacute definida como typedef unsigned short wchar_t para el
caso de compilar como C Recuerde que este compilador puede trabaja indistintamente con coacutedigo
C y C++ y que un unsigned short ocupa 2 bytes ( 224)
En C++ wchar_t es una palabra clave que representa un tipo especial el caraacutecter ancho o
extendido Su espacio de almacenamiento depende de la implementacioacuten (ver 221a1) En el
caso de BC++ 55 ocupa el mismo espacio que un int es decir 4 bytes En las cadenas de
caracteres anchos se ocupan igualmente 4 bytes por caraacutecter
Ejemplos
wchar_t ch = LA
wchar_t str = LABCD
wchar_t nulo = L0 caraacutecter nulo ancho
423