06 programacion en c++

47
§3 Identificación del endianness del sistema Si estamos escribiendo una aplicación o librería muy general, que en algún punto deba tener en cuenta el endiannes de la máquina anfitriona, es posible averiguarlo fácilmente mediante una directiva que podemos utilizar posteriormente en las sentencias correspondientes según el resultado. Serían las siguientes: const unsigned int myOne = 1; #define IS_BIGENDIAN (*(char*)(&myOne) == 0) #define IS_LITTLEENDIAN (*(char*)(&myOne) == 1) Observe que la dirección de myOne (que es un puntero-a-int) es convertida a puntero-a- char mediante el cast correspondiente; a continuación se compara el contenido de esta dirección con cero y con 1. En realidad se está comparando el primer bite de myOne. El truco está precisamente en comparar el contenido del primer byte (la comparación myOne == 1 sería siempre cierta). El resultado es 0 (falso) o 1 (cierto) según el modelo del sistema utilizado, que corresponderá o no, con el del hardware subyacente según el caso. Por ejemplo, en una máquina Intel&Windows, el programa #include <cstdlib> #include <iostream> const unsigned int myOne = 1; #define IS_BIGENDIAN (*(char*)(&myOne) == 0) #define IS_LITTLEENDIAN (*(char*)(&myOne) == 1) int main(int argc, char *argv[]) { std::cout << "Esta maquina es Big-endian: " << (IS_BIGENDIAN? "Cierto" : "Falso") << std::endl; std::cout << "Esta maquina es Little-endian: " << (IS_LITTLEENDIAN? "Cierto" : "Falso") << std::endl; system("PAUSE"); return EXIT_SUCCESS; } Produce la siguiente salida: Esta maquina es Big-endian: Falso Esta maquina es Little-endian: Cierto Presione cualquier tecla para continuar . . . 3. Elementos léxicos "In the software professions reading is like breathing. Stopping can be dangerous to your health". David Weber C/C++ Users Journal. Marzo 1996 "Twho C++ tutorials".

Upload: ferbuifo

Post on 29-Nov-2015

51 views

Category:

Documents


2 download

TRANSCRIPT

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

Ejemplos

wchar_t ch = LA

wchar_t str = LABCD

wchar_t nulo = L0 caraacutecter nulo ancho

423