You are on page 1of 46

3.2.

3e Secuencias de escape
1 Sinopsis Como se indic al tratar del cdigo ASCII ( 2.2.1a), existen 33 de estos caracteres que no tienen representacin grfica; son los denominadoscaracteres de control. Con el fin de poder representarlos en el cdigo fuente, se recurri al artificio de representarlos utilizando una barra invertida (\) seguida de otra serie de caracteres.

2 Secuencias de escape Las secuencias de caracteres en las que el primero es la barra invertida, se denominaron secuencias de escape y aunque originariamente se utilizaron para la representacin de los caracteres de control, por extensin pueden representarse de este modo todos los cdigos ASCII. Adems se dispone de algunos smbolos predefinidos para los caracteres ms frecuentes. Por ejemplo, \n se utiliza para representar el carcter nueva lnea (decimal 10). Los smbolos utilizados se muestran en la tabla adjunta. Secuencia Valor \a \b \f \n \r \t \v \\ \' \" \? \O \xH \XH Ejemplo char campana = '\a'; cout << campana << endl; // carcter ASCII 7 // genera un sonido audible 0x07 0x08 0x0C 0x0A 0x0D 0x09 0x0B 0x5c 0x27 0x22 0x3F Smbolo BEL BS FF LF CR HT VT \ ' " ? Descripcin Sonido audible (bell) Retroceso (backspace) Salto de formato (formfeed) Saltar una lnea (linefeed) Retorno de carro (carriage return) Tabulacin horizontal (H Tab) Tabulacin vertical (V Tab) Barra invertida (backslash) [2] Apstrofo (comilla simple) Doble comilla Interrogacin O = cadena de hasta tres dgitos octales H = cadena de dgitos hexadecimales H = cadena de dgitos hexadecimales

cualquiera cualquiera cualquiera cualquiera cualquiera cualquiera

3 La barra invertida ( \ ) se utiliza junto con nmeros octales o hexadecimales [3] para representar smbolos ASCII ( 2.2.1a), incluyendo los denominados caracteres de control (tambin llamados caracteres no imprimibles) que no tienen representacin directa en ningn carcter.

En una secuencia de escape se pueden utilizar hasta tres caracteres en octal o cualquier nmero de caracteres en hexadecimal. Siempre que los valores estn dentro del rango legal para el tipo char (de 0 a 0xff para C++Builder).

3.1 Octal Rango: \0 a \377 Ejemplos: \0 \03 \07 \013 \077

Carcter nulo (fin de cadena) Ctr-C Bell Vertical TAB ?

3.2 Hexadecimal Rango \x00 a \xFF Ejemplos: \0 \x3 \x7 \xB \x3F

Carcter nulo (fin de cadena) Ctr-C Bell Vertical TAB ?

4 Los nmeros mayores que los indicados generan un error de compilacin: Numeric constant too large. Por ejemplo, el octal \777 es mayor que el mximo permitido (\377), por lo que producira un error. El primer carcter no octal o no hexadecimal que se encuentre en una secuencia octal o hexadecimal respectivamente, seala el final de la secuencia de escape. Por ejemplo: printf("\x072.1Un Sistema Operativo"); La sentencia anterior debera ser interpretada como el hexadecimal \x07 (BEL) y 2.1 Un Sistema Operativo, aunque quizs el compilador lo interprete como hexadecimal \x072 (el carcter "r") y la cadena literal .1Un sistema Operativo. Para evitar este tipo de ambigedades debe escribirse: printf("\x07" "2.1Un Sistema Operativo");

Tambin pueden darse ambigedades si una secuencia de escape en octal es seguida por un nmero no octal. Por ejemplo, dado que los dgitos 8 y 9 no son octales vlidos, la constante \258 puede ser interpretada como una constante de dos caracteres \25 (Ctrl-U) y un 8.

5 Trigrafos Con la extensin de la informtica a pases distintos del mbito anglosajn, se presentaba con frecuencia el problema de tener que escribir determinados caracteres del lenguaje C++ (Us-ASCII) que no estaban presentes en determinados teclados. Por ejemplo, en la mayora de teclados en Espaol, no existe la tilde ~ como un carcter independiente, lo que no es inconveniente para la escritura normal, ya que la nica ocurrencia en este signo en Espaol es en la letra ee "" que s dispone de su correspondiente tecla. Pero la referida ausencia de la tilde como smbolo independiente, resulta una molestia para los programadores, ya que el fuente requiere en ocasiones incluir dicho smbolo. Para resolver el problema se adopt el convenio que estos caracteres conflictivos podan representarse en el cdigo fuente mediante parejas y ternas de caracteres, los denominados dgrafos y trgrafos, que se muestran en la tabla adjunta. Trgrafo Carcter Dgrafo ??= # %: ??( [ <: ??) ] :> ??/ \ ??' ^ ??< { <% ??> } %> ??! | ??~ Nota: la interpretacin de estos trgrafos retarda considerablemente la accin del compilador, por lo que Borland C++ incluye un traductor especfico, el programa trigraph.exe, que puede traducir el cdigo fuente antes de la compilacin [4]. Tema relacionado: Representacin explcita de operadores lgicos ( 4.9.8).

3.2.3f Constantes de cadena


1 Sinopsis Las constantes de cadena, tambin llamadas cadenas literales o alfanumricas ("String literals"), son utilizadas para albergar secuencias de caracteres alfanumricos, y forman una categora especial dentro de las constantes, aunque tambin pueden ser consideradas un caso especial de matrices de caracteres ( 4.3.4). Se representan en el fuente como una secuencia de caracteres entre comillas dobles ("): "Esto es una cadena literal!" L"Esto es una cadena de caracteres anchos"

Vistas con cierta perspectiva, las cadenas literales aparecen como un tipo algo extrao, que en

cierta forma desentona del resto de entidades del universo C++ y que no deberan tener cabida en l. En realidad hay algo de esto; representan una herencia de su antecesor C, en el que se utilizan estas "extraas" construcciones para almacenar texto alfanumrico en el que su punto final se identifica mediante el carcter nulo [2]. El texto de una cadena literal puede contener cualquier carcter del juego de caracteres imprimibles ASCII ( 2.2.1a). Para representar los caracteres no imprimibles se utilizan las denominadas secuencias de escape ; un truco que consiste en sustituir cada carcter no imprimible por una secuencia de dos o tres caracteres. Naturalmente, una cadena literal no debe contener un carcter nulo en su interior (que como hemos indicado seala el final de la cadena); en caso contrario, al aplicarse las funciones de Librera Estndar clsicas (heredadas de C) el resultado es impredecible.

1.1 El punto importante a entender aqu podra sintetizarse en que, desde la ptica C++, las cadenas literales: Representan valores (datos) constantes. Para el compilador son en realidad matrices de caracteres constantes, aunque les permite una sintaxis algo especial en atencin a que el antiguo cdigo C sea compatible con los compiladores C++ . Si la cadena no est precedida por la letra L, es una matriz de caracteres tipo const char ( 3.2.3), tambin denominada cadena estrecha u ordinaria ("Narrow string literal"). Si la cadena est precedida por la letra L, los miembros de la matriz son caracteres anchos ( 2.2.1a1) del tipo const w_char, y se denomina cadena ancha ("Wide string literal"). Estos objetos tienen almacenamiento esttico en el sentido indicado en 2.2.6; es decir, que el compilador conoce los valores en tiempo de compilacin, y que probablemente sean guardados en el segmento ( 1.3.2) [4].

1.2 Generalmente aparecen a la derecha en expresiones de asignacin o como parmetros de funciones; pueden aparecer incluso como valores devueltos por funciones. Ejemplos: char* ptr = "Hola mundo"; printf("%s\n", "Soy una cadena literal"); cout << "acabo de llegar" << endl; return "Se termina la funcin";

2 Secuencias de escape Dentro de las comillas se pueden representar caracteres especiales (no imprimibles) mediante secuencias de escape ( 3.2.3e). Por ejemplo, el cdigo: "\t\t\"Nombre\"\\\tDireccin\n\n" Se representa como: "Nombre"\ Direccin

"Nombre" es precedido por dos tabulaciones; Direccin esta precedido por una tabulacin. La lnea va seguida de dos nueva lnea (NL). La secuencia \" proporciona las comillas interiores. Si se

compila con la opcin -A para compatibilidad ANSI, la secuencia de escape "\\", es traducida por el compilador a "\".

3 Como hemos sealado, en C++ las cadenas alfanumricas son tcnicamente matrices de caracteres constantes; se almacenan internamente como secuencias de caracteres ms un carcter final nulo '\0', lo que significa que el almacenamiento usado es igual a la longitud visible de la cadena mas uno. Segn esto, la cadena nula "" es almacenada como un solo carcter '\0', y no hay ms lmite que la memoria disponible para la longitud posible de una cadena. Por ejemplo, la cadena "Hola\n" se guarda internamente como:

H o l a \n \0

Nota histrica: El mtodo de identificar el final de cadena mediante un carcter nulo es ineficiente, y aparte de que no permite utilizar cadenas que contengan un carcter nulo en su interior (por ejemplo ficheros binarios), su manejo conlleva problemas de rendimiento [3]. Aparentemente, la razn por la que C y C++ utilizan este mtodo se debe a que C se desarroll sobre mquinas Unix ( 1), y a su vez este sistema operativo fue desarrollado inicialmente sobre una mquina DEC ("Digital Equipment Corporation") PDP-7, que tenan un tipo de dato denominado ASICZ (ASCII con un "Zero" al final) que era directamente reconocible por su ensamblador.

4 Peculiaridades En el prembulo sealamos que una cadena literal es "un tipo de matriz de caracteres constantes". Se trata pues de verdaderas matrices, aunque la coletilla "de caracteres constantes" es importante. Significa esto que no se trata de ningn nuevo tipo de dato, solo un tipo particular de matrices. En consecuencia, una cadena como "Hola" es del tipo const char [5] (matriz de caracteres constantes de cinco elementos). Su nica singularidad es que el compilador C++ les permite ciertas formas particulares de definicin y declaracin que les confiere cierta personalidad. Por ejemplo, el hecho de inicializarlas directamente con expresiones como las sealadas 1.2 ; o que aada automticamente el carcter nulo de terminacin a los caracteres explcitamente indicados por el programador. Respecto a esto ltimo, solo tiene justificacin histrica, porque el carcter nulo se utilizaba en las antiguas funciones de librera para indicar el final de la cadena. Por esta razn, aunque es posible incluir caracteres nulos dentro de las cadenas literales. Por ejemplo: "Hola\0 mundo", no est garantizado que funcione en todos los casos (ser malinterpretado por las funciones printf, strcpy y strlen de la Librera Estndar). Ejemplo: char* ptr = "Hola\0 mundo"; printf("%s\n", ptr); Salida: Hola

5 Una cadena nula (vaca) se representa "" o "\0"; tiene un solo carcter; el carcter nulo (ver a continuacin). Observe que desde el punto de vista del Rvalue, la constante de cadena "A" es A\0, mientras que la constante carcter ( 3.2.3d) 'A' es A.

Se considera que la longitud de un NTBS es el nmero de caracteres que preceden al de terminacin, de forma que la cadena nula tiene longitud 0 (aunque en realidad contiene un carcter). Sin embargo, el valor de la cadena incluye el carcter de final. Conviene no confundir una constante de cadena (matriz) de un solo carcter con un carcter char, constante ( 3.2.3d) o variable ( 2.2.1a). La cadena de un solo carcter es necesariamente la cadena nula, su nico elemento es el de fin de cadena. Ejemplo: char // L.1: variable x1 tipo char // valor == ASCII a == 97 decimal const char x2= 'a'; // L.2: constante x2 tipo const char char* x3 = "a" ; // L.3: variable x3 tipo puntero-a-char // seala a cadena de dos caracteres, 97 y 0 decimal const char* x4 = "a"; // L.4: variable x4 tipo puntero a constante carcter char x5[1]= 'a' ; // L.5: variable x5 tipo matriz de un carcter // valor x[0]== a == 97 decimal x1= 'a' ;

Los objetos representados por los Rvalues ( 2.1.5) de las expresiones anteriores son de distinto tipo y se almacenan con tamaos distintos. La primera, segunda y quinta son constantes carcter (const char); la tercera y cuarta son cadenas (matrices) de dos caracteres. En lo que respecta a los cinco objetos definidos, x1 es una variable char; x2 es una constante char; x3 es un puntero a cadena de caracteres; x4es un puntero cadena de caracteres constantes, y x5 es una matriz de caracteres de un elemento. Es tambin muy importante sealar que la asignacin: str = "AEIOU"; solo es posible si str se ha declarado previamente como puntero a carcter, es decir: char* str; // g

Aunque se puede declarar y definir en la misma sentencia (preferible): char* str = "AEIOU"; // h

El lector observador advertir en la expresin anterior una evidente inconsistencia en la gramtica del C++. En efecto, como se ha sealado, las cadenas literales son de "caracteres constantes". En consecuencia, no asignables a punteros tales como los definidos en g o h ; tcnicamente "punteros a carcter". Tericamente solo hubiese sido aceptable la asignacin a puntero-acarcter-constante, tal como:

const char* str = "AEIOU";

// i

ya que un puntero-a-constante-tipoX no es intercambiable por un puntero-a-tipoX ( 4.2.1a). La razn de esta inconsistencia en la definicin de las cadenas literales, hay que buscarla en otra de las desafortunadas herencias del C clsico, y en la necesidad de mantener compatibilidad con millones de lneas de cdigo existente. En C y en las primitivas versiones de C++, las cadenas literales eran consideradas como de tipo char* (puntero a carcter). Aunque la mayora de compiladores C++ permiten este tipo de sentencias por razones de tipo histrico, parece que tal permisividad tiende a ser "deprecated" (a extinguir), de forma que las ltimas revisiones de algunos compiladores pueden lanzar una advertencia o error en tales circunstancias. La forma cannica de definir este tipo de cadenas sera: const char str[] = "AEIOU";

La expresin h define una matriz de seis caracteres constantes (almacenado en algn sitio), que no tiene identificador simple (nombre). Tambin define un puntero, str al primer elemento de la matriz (ms formalmente: es un puntero a carcter). Por tanto, a falta de un nombre, la matriz tiene que ser accedida a travs del puntero (que tendr que ser tratado como tal -puntero-). Sin embargo, las expresiones: char char char char char arr[] = "AEIOU"; // j arr[6] = "AEIOU"; arr[6] = {'A','E','I','O','U','\0'}; arr[6] = {'A','E','I','O','U',''}; arr[6] = {'A','E','I','O','U',0};

definen arr como matrices de caracteres de 6 elementos (las 5 expresiones son equivalentes); en estos casos cada matriz puede ser accedida por su nombre (que tienen que ser tratado como tal identificador-) y no son de contenido constante. Todo esto tiene varias implicaciones: En el primer caso (h ) , str es un puntero; un objeto que puede ser usado con el lgebra de punteros. Por ejemplo, es vlida la expresin: str++ que equivale a: str = str+1;. En los otros cinco casos (j ), arr es un nemnico que representa una matriz, y la expresin arr++, que equivale a: arr = arr+1; es ilegal. El operando arr+1 es tratado como (&arr[0])+1, lo que es correcto (a un puntero se le puede sumar un entero). La asignacin no sera correcta porque intentara asignar el puntero, &arr[1], a la matriz arr. No olvidar que en el primer caso *str no significa la matriz "AEIOU", solo el primer elemento 'A', por lo que no tiene sentido intentar la asignacin *str = "aeiou";, ni siquiera *str = "a";; solo es posible *str = 'a'; [1]. Recuerde que C++ no tiene operadores para tratar las matrices como una unidad, es decir, para hacer una asignacin del tipo: x = "aeiou". Si tiene en cambio poderosas funciones en su Librera Estndar para hacer todo tipo de manipulaciones con cadenas alfanumricas. Es tambin importante distinguir otra diferencia entre las expresiones: char a1[6] = "AEIOU\0", *p1 = &a1[0]; char* a2 = "AEIOU";

Ambas producen matrices de caracteres absolutamente idnticos en contenido y tamao, pero a1 es una matriz, por lo que sus elementos podran ser alterados usando el identificador. Por ejemplo: es vlido a1[1]= 'e', o su equivalente: *(p1+1)='e';. En cambio, un intento anlogo sobre el segundo obliga a usar necesariamente la versin con puntero: *(a2+1)='e'. Adems de que por las razones ya expuestas [2] el resultado no est garantizado. Si se quiere que los caracteres de una cadena puedan ser modificados lo mejor es incluirlos en una matriz como en a1. Es posible todava la asignacin: a2 = "aeiou"; En este caso, el compilador almacena en algn sitio la cadena "aeiou\0" y asigna a a2 la direccin del primer elemento. A partir de ahora es accesible mediante a2, pero la primitiva cadena "AEIOU", que sigue existiendo en su sitio, se ha perdido irremisiblemente, no es accesible de ningn modo, aunque sigue malgastando espacio de memoria. Tambin es posible declarar cadenas de caracteres anchos con el prefijo L como en el ejemplo: wchar_t* wptr = L"aeiou"; en este caso wptr seala una cadena de caracteres anchos ( tipo const wchar_t. 2.2.1a1); la cadena es del

Para saber la longitud de una constante literal, es necesario que el programa repase la cadena hasta encontrar el carcter de fin de cadena, lo que se consigue con la funcin de librera strlen (incluida en la cabecera estndar <string.h>), que proporciona la longitud sin contar el carcter final.

6 Concatenacin de cadenas Las cadenas literales adyacentes separadas solo por un especio son automticamente concatenadas durante la fase de preprocesado ( 1.4.1) de la compilacin. Por ejemplo: "Hola" " mundo", es equivalente a "Hola mundo". Tambin puede usarse la barra invertida ( \ ) como smbolo de continuacin para extender una cadena literal ms all del lmite de una lnea: puts("En realidad, esto es \ una cadena de una linea"); char *p = "Esto es en otra cadena, " "tambin de una sola lnea.";

La concatenacin suprime el carcter nulo de final en las cadenas intermedias y mantiene el de la ltima. Esta operacin no altera el significado de los caracteres que intervienen en las cadenas concatenadas. Por ejemplo, la concatenacin "\xA" "B" Produce la cadena "\xAB"

que tiene tres caracteres: el hexadecimal '\xA'; el carcter 'B', y el caracter final nulo '\0'. En vez del carcter hexadecimal '\xAB'. La concatenacin de cadenas anchas y estrechas tiene resultados impredecibles.

3.2.3g Constantes de enumeracin


1 Sinopsis Existe un tipo especial de variables denominadas variables enumeradas o simplemente enumeraciones ( 4.8 ). Se caracterizan por poder adoptar valores entre una seleccin de constantes enteras denominadas enumeradores, cuyos valores son establecidos en el momento de la declaracin del nuevo tipo. Como se ha sealado, son enteros y (una vez establecidos) de valor constante, razn por la que se los denomina tambin constantes de enumeracin. Ejemplo: enum estado { MALO =0, REGULAR =1, BUENO =2, EXTRA =3 };

La sentencia anterior declara estado como un tipo de variable de enumeracin. Los miembros de esta clase pueden adoptar los valores indicados y son representados por los nemnicos: MALO, REGULAR, BUENO y EXTRA. Estas cuatro constantes son los enumeradores del nuevo tipo. Como advertencia a lo indicado hasta aqu, no confundir la enumeracin (la variable) con los enumeradores (las constantes enteras que delimitan el conjunto de valores posibles de la variable). Tambin resaltar que estado es un nuevo tipo de variable, en el mismo sentido que, por ejemplo, int o char son tipos, y que posteriormente es posible declarar instancias concretas del nuevo tipo y su valor correspondiente. Por ejemplo: estado mi_estado = EXTRA; estado tu_estado = REGULAR; std::cout << "Mi estado actual es: " << mi_estado << endl // -> Mi estado actual es: 3

En el caso anterior, estado es una enumeracin (tipo genrico), mientras que mi_estado y tu_estado son instancias concretas del nuevo tipo, actualmente sus valores respectivos son 3 y 1. No confundir el tipo enum (genrico) con un tipo enum concreto, una "instancia" (variable enumerada) de ese tipo, ni con los valores concretos (constantes de enumeracin) que puede adoptar Para facilitar la legibilidad, los identificadores de las constantes de enumeracin son nemnicos, y sus nombres suelen estar en maysculas, debido a una larga tradicin C/C++ de representar de este modo las constantes.

Ya hemos sealado que estas constantes (enumeradores) son de tipo entero, por lo que pueden ser utilizadas en cualquier expresin donde sean permitidas las constantes enteras. Sus identificadores deben ser nicos dentro del mbito de la declaracin enum. Se permiten inicializadores negativos; los valores que adoptan los enumeradores suelen ser nicos (aunque se permiten duplicidades). Para una visin ms detallada de las declaraciones de estas constantes, ver enumeraciones ( 4.8 ) y la explicacin que sigue sobre la palabra clave enum.

2 Sintaxis: enum [<nombre-de-tipo>] {<nombr-const> [= <valor>], ...} [lista_var]; Puede omitirse la palabra clave enum siempre que el nemnico <nombre-de-tipo> no sea empleado para nada ms en el mismo mbito. Ejemplo: calidad { BUENA, REGULAR, MALA }; En este caso el compilador presupone que calidad es un enumerador, y no debe existir otra definicin en el mismo mbito de nombres. En otras palabras: calidad no debe utilizarse en el mismo mbito para designar otro objeto. <nombre-de-tipo> es una etiqueta opcional que identifica al conjunto. Puede omitirse si no se va a usar ninguna otra variable de este tipo de enumeracin. Ejemplo: enum { CIERTO, DUDOSO, FALSO }; <nombr-const> es el nombre de la constante de enumeracin (enumerador), a la que opcionalmente puede asignarse el valor definido por<valor>. En el ejemplo anterior son tres: CIERTO, DUDOSO y FALSO. <valor> debe ser un entero (ya se ha sealado que los enumeradores son constantes enteras). Si no se especifica ningn valor, se supone que es <previo> + 1, donde <previo> es el valor del enumerador anterior de la lista (el valor por defecto para el primero es cero). <valor>puede ser cualquier expresin que resulte en un entero positivo o negativo (despus de posible conversin a entero). <lista_var> es una lista opcional de variables que son declaradas como del tipo enum que se define.

En el ejemplo que sigue se declara un tipo de enumeracin de nombre genrico calidad; las variables de este tipo pueden adoptar tres valores: 0, 1 y 2, identificados respectivamente por los nemnicos BUENO, REGULAR y MALO; adems se definen dos variables del nuevo tipo: nota yestado. enum calidad { BUENO, REGULAR, MALO }, nota, estado;

3 Descripcin

La palabra clave enum define una enumeracin, una lista de los valores (constantes enteros) que puede tomar una un tipo especial de variable a las que denominaremos variables enumeradas, con la particularidad de que, para mayor legibilidad, esta lista de valores esta representada por nemnicos. Por ejemplo, la declaracin: enum dias { DOM, LUN, MAR, MIE, JUE, VIE, SAB } diaX; establece un tipo enum al que se identifica por dias; las variables de este tipo pueden adoptar un conjunto de seis valores enteros 0, 1, 2, 3, 4, 5, 6 (enumeradores) representados por los nemnicos DOM, LUN,...,SAB. Adems se define una variable enumerada diaX de este tipo. enum modelo { ULT =-1, BW40=0, C40, BW80, C80, MONO =7 }; En este ejemplo se define un tipo enum al que identificamos por la etiqueta modelo; las variables de este tipo pueden adoptar 6 valores (-1, 0, 1, 2, 3 y 7) que se identifican con los nemnicos: ULT, BW40, C40, BW80, C80 y MONO. Los valores asignados a los enumeradores dependen del formato de la declaracin y de la presencia de inicializadores opcionales. En el ejemplo: enum color { ROJO, VERDE, AZUL }; ROJO, VERDE y AZUL son enumeradores del tipo color y pueden ser asignados a cualquier variable de tipo color o a cualquier otra variable de tipo entero. Los valores asignados a los enumeradores son: ROJO == 0, VERDE == 1, AZUL == 2. En el ejemplo siguiente: enum color { ROJO, AZUL=2, VERDE = AZUL - 1 }; los enumeradores reciben los valores: ROJO = 0, VERDE = 1, AZUL = 2. Adems, como puede comprobarse, las expresiones de inicializacin pueden incluir enumeradores previamente declarados. Los valores de los enumeradores no tienen porqu ser nicos, como en el ejemplo que sigue. enum estado { BUENO, MALO = 1, REGULAR = 1 };

3.2.6 Puntuadores
1 Sinopsis Los signos de puntuacin del lenguaje C++ juegan el mismo papel que sus homnimos en el lenguaje natural escrito. Conocidos tambin comopuntuadores [1], son los que se citan a continuacin. La mayora de ellos tienen un doble uso y en ocasiones funcionan tambin comooperadores ( 4.9).

[ ] ( ) { } , ; : ... * = # ! % ^ & + | ~ \ ' " < > ? . /

2 Corchetes [ ] Los corchetes indican subndices de matrices uni y multi dimensionales. char ch, str[] = "Cadena de caracteres"; int mat[3][4]; // Matriz de 3 x 4 ch = str[3]; // cuarto elemento

3 Parntesis ( ) Los parntesis sirven para agrupar expresiones; alterar la precedencia normal de los operadores y su asociatividad; aislar expresiones condicionales; indicar llamadas a funciones, y sealar los parmetros de estas. La sintaxis de C++ exige indefectiblemente el uso de parntesis en mltiples ocasiones. En los ejemplos que siguen se muestran algunos usos. d = c * (a + b); if (d == z) ++x; for (x =1; x<10; x++) func(); int func(); int (*fptr)(); fptr = func; // // // // // // // modifica la precedencia normal imprescindible en la sentencia if imprescindible en la sentencia for seala llamada a funcin declara funcin declara puntero a funcin asigna valor al puntero. 4.2.4a)

Observe que en el ltimo caso, la ausencia de parntesis equivale a &func (

Se recomienda el uso de parntesis en las macro-definiciones para evitar problemas potenciales en la expansin. Por ejemplo: #define CUBO(x) ((x) * (x) * (x))

4 Llaves { } Los pares de llaves { } sealan el comienzo y final de una sentencia compuesta, es decir, bloques de cdigo (grupos de sentencias que son tratadas como una unidad). Constituyen el segundo paso (despus de las sentencias) en la estructuracin y compartimentacin del cdigo C++: if (d == z) { ++x; func(); }

Un bloque es una sentencia compuesta, se trata de una sucesin (que puede estar vaca) de sentencias delimitadas por un par de corchetes { }. Desde el punto de vista sintctico, un bloque puede ser considerado como una sola sentencia. Juega un papel importante en el mbito (scope) de los identificadores, puesto que un identificador declarado dentro de un bloque tiene un mbito

que comienza en el punto de la declaracin y termina en el corchete final. Sin embargo, el mismo identificador puede ser ocultado por otro del mismo nombre declarado en un bloque interior al primero. Dentro de las posibilidades de memoria, los bloques pueden ser anidados a cualquier nivel (profundidad). Despus del corchete de cierre } no se necesita el punto y coma ; de fin de sentencia if (statement) {...}; else

// punto y coma ilegal !!

Nota: las llaves sirven tambin en C++ para otros usos distintos de la pura delimitacin de bloques de cdigo. Por ejemplo, en la definicin de estructuras, uniones y clases, en cuyo caso si puede ser necesaria la inclusin del punto y coma despus de la llave de cierre }.

5 Coma , La coma como puntuador se utiliza para separar los elementos en las listas de parmetros de una funcin: void func(int n, float f, char ch); La coma se usa tambin como un operador en las expresiones con coma ( 4.10.5). Es posible mezclar los dos usos (separador en lista de parmetros y operador), pero deben usarse parntesis para distinguirlos.

6 Punto y coma ; El punto y coma ; es el signo de fin de sentencia. Cualquier expresin legal C++ terminada por un punto y coma (incluyendo la expresin vaca - un punto y coma aislado-) es interpretado como una sentencia, conocidas como sentencia-expresin ( 4.10). La expresin se evala y el resultado se descarta; si no tiene efectos colaterales, C++ la ignora. a + b; ++a; ; // evala a + b, descarta el resultado // efecto lateral en 'a', se descarta el valor ++a // expresin vaca = sentencia nula

El punto y coma se usa a veces para crear sentencias nulas: for (i = 0; i < n; i++) { ; // sentencia nula (hacer nada) }

7 Dos puntos : Los dos puntos se utilizan para sealar sentencias etiquetadas ( 4.10.1):

comienzo: x=0; ... goto comienzo;

// comienzo es la etiqueta

8 Puntos suspensivos ... Los puntos suspensivos, tambin llamados elipsis, son tres puntos, seguidos y sin espacios intermedios; tienen varios usos en C++. Se utilizan en las relaciones de argumentos formales de las funciones, cuando estas pueden aceptar un nmero variable de argumentos o pueden ser de tipo variable ( 4.4.1). Por ejemplo: void func(int n, char ch,...); Este prototipo de funcin declara que func est definida de modo que debe ser llamada con, al menos, dos argumentos: un int y un char. Adems puede tener un cierto nmero de argumentos adicionales (puede omitirse la coma antes de la elipsis). Se utiliza tambin para indicar que un manejador de excepciones ("handler") puede capturar una excepcin de cualquier tipo ( 1.6.2). Ejemplo: try { // bloque-intento ... } catch (...) { // captura cualquier excepcin cout << "Se ha producido una excepcin!" << endl; ... }

Nota: como podis ver, en ocasiones, mi uso particular en los ejemplos de los tres puntos, es para indicar cualquier nmero de sentencias. Espero que no sea motivo de confusin. Desde luego, en el caso anterior sera ms correcta la notacin: try { // bloque-intento // ... } catch (...) { // captura cualquier excepcin cout << "Se ha producido una excepcin!" << endl; // ... }

9 Asterisco * El asterisco * puede ser utilizado en C++ de tres formas: como una declaracin de tipo de variable (variable de puntero 4.2 ); como operador de indireccin (tambin llamado operador de dereferencia 4.9.11a) y como operador de multiplicacin. Ejemplos:

char* char_ptr; x = *int_ptr; l = 2 * 3.14 * r;

// declara puntero a carcter // operador de indireccin // operador multiplicacin

10 Signo igual = El signo igual = separa la declaracin de variables de las listas de inicializacin: char array[5] = { 1, 2, 3, 4, 5 }; Recordemos que, al contrario que en C, donde las declaraciones no pueden estar precedidas por ningn cdigo, deben ir al principio, en C++, las declaraciones de cualquier tipo pueden aparecer en cualquier punto del cdigo (con algunas restricciones). En la lista de argumentos de una funcin, el signo igual indica el valor por defecto para un parmetro: int f(int i = 0) { ... } // el valor por defecto de k es cero 4.9.2). Ejemplo:

El signo igual es tambin utilizado como operador de asignacin ( x = y; z += 5;

11 Almohadilla # Si la almohadilla # aparecen en el primer carcter (distinto de espacio en blanco) de una lnea, seala directivas de preproceso ( 4.9.10). En este caso, es un operador especfico de la fase de preproceso del cdigo fuente. Significa una opcin del preprocesador ( 1.4) que no tiene porqu estar asociada necesariamente a generacin de cdigo. Las directivas se sitan generalmente al comienzo del programa, aunque legalmente pueden aparecer en cualquier punto. Ejemplos de directivas de preproceso: # (null directive) #define NULO \0 #include <stdio.h>

4. Estructura del lenguaje


1 Sinopsis

Esta parte proporciona una definicin formal del lenguaje C++, describiendo las formas en que pueden agruparse correctamente los tokens ( 3.2), palabras que constituyen el lenguaje entendible por el compilador, para formar declaraciones; expresiones y otras unidades significativas. Para su anlisis lo hemos descompuesto en 13 grupos segn la clasificacin que sigue: 4.1 Declaraciones: Objetos Referencias & definiciones Definicin provisional mbito Visibilidad Duracin Unidad de compilacin Enlazado Sintaxis de declaraciones Conversiones aritmticas Inicializacin Especificadores de clase de almacenamiento Modificadores auxiliares Modificadores de funcin 4.2 Punteros Puntero a objeto Declaracin de punteros Aritmtica de punteros Referencias Puntero a funcin 4.3 Matrices Declaracin de matrices Matrices alfanumricas Matrices de punteros Matrices de matrices 4.4 Funciones Declaracin Definicin Argumentos formales y actuales Llamada y conversin de argumentos Valores devueltos 4.5 Estructuras Declaracin de estructuras Inicializacin Operaciones permitidas Acceso a miembros Estructuras y funciones Matrices de estructuras Punteros a estructuras Estructuras auto-referenciadas 4.6 Campos de Bits 4.7 Uniones 4.8 Enumeraciones

Expresiones Asociatividad y precedencia de operadores Orden de evaluacin Errores y desbordamientos Expresiones con coma 4.9 Operadores Aritmticos Asignacin Manejo de Bits Operador Coma Condicional Op. de igualdad Op. Lgicos Modelado de tipos Op. de Preproceso Op. de puntero Relacionales sizeof typeid Op. primarios Op. aadidos Op. Unitarios Sobrecarga de Operadores Operador :: Operador new Operador delete 4.10 Sentencias Sentencias de etiqueta: case, default Sentencias de seleccin: if else, else if, switch Sentencias de iteracin: while, do...while, for Sentencias de salto: break, continue, goto, return 4.11 Clases Creacin Declaracin Nombres de Clases mbito de nombres Instanciado de Clases this (palabra reservada) Miembros estticos Clases polimrficas Funciones virtuales Funciones dinmicas Clases abstractas 4.12 Plantillas Funciones genricas Clases genricas Aunque las secciones anteriores describen completamente el lenguaje desde una perspectiva formal, hemos aadido un captulo adicional (4.13) dedicado a los tecnicismos. En l se incluyen algunos consejos y reglas de buena prctica para la programacin C++, as como algunos "idioms"

(formas y tcnicas particulares) que, en lenguajes tan complejos como el presente, constituyen una parte importante del "know-how" de los expertos.

4.1 Declaraciones
1 Sinopsis Una declaracin es una clusula que introduce nombres en una unidad de compilacin ( 1.4.2) o redeclara nombres introducidos por declaraciones previas. La norma seala que una declaracin especifica la interpretacin y atributos de estos nombres (como tipo de enlazado y de almacenamiento si es un objeto), as como las condiciones para que una declaracin no sea tambin una definicin. En la pgina adjunta se muestra su gramtica ( Gramtica). Cada una de las introducciones unitarias que puede existir en una declaracin es un declarador ("declarator"). As pues, un declarador introduce un nombre, o redeclara uno declarado previamente. La pgina adjunta muestra su gramtica ( Gramtica).

El presente captulo repasa este importante concepto y otros relacionados tales como: objetos, clases de almacenamiento, tipos, mbito,visibilidad, duracin y enlazado. El mbito, visibilidad, duracin y enlazado son propiedades o caractersticas que determinan las porciones del programa que pueden utilizar legalmente un identificador para acceder a su objeto. Es esencial un conocimiento general de estos conceptos antes de acometer una definicin de declaracin o la exposicin de su sintaxis. En el epgrafe 4.1.11 exponemos el concepto espacio de nombres; un recurso de C++ para manejar los identificadores, que permite dividir el espacio total de nombres en subespacios distintos e independientes cuya existencia tambin es dada a conocer mediante una declaracin.

4.1.1 Entidades
1 Presentacin En relacin con los conceptos que aqu nos incumben, consideramos que una entidad ( 1.2.1) a la que corresponde una zona de almacenamiento, es un objeto, y que el contenido de esta zona de memoria puede ser de dos tipos: Un valor (o conjunto de valores) fijo o variable. Lo denominamos entidad-valor u objetovalor. Un algoritmo con informacin sobre manipulacin de datos. Lo denominamos entidadalgoritmo o simplemente algoritmo.

Respecto a los objetos-valor, una posible clasificacin podra dividirlos en las siguientes categoras:

Agregados o matriz o estructura o unin o clase, unin. Funciones Escalares o Aritmtico o Enumeracin o Booleano o Puntero o Referencia void

void ( 2.2.1) es un tipo especial con un valor muy particular: "ausencia de valor". Los escalares son de caractersticas tales que su "valor" no pueden ser descompuestos en partes ms pequeas, por ejemplo, un entero; un valor lgico (cierto-falso), etc. Las funciones ( 4.4) son principalmente algoritmo, ya que estn asociadas a ciertas operaciones (cierta computacin), pero por convencin se les puede asignar un "valor", es el que devuelven (puede ser void). Por su parte los agregados comparten la caracterstica de que su "valor" puede ser descompuesto en elementos ms simples (escalares).

2 El papel de las declaraciones Haciendo un smil social, podramos decir que las declaraciones son las encargadas de "presentar" al compilador cualquier entidad que deba existir en el programa. Son por tanto, el Chambeln de la sociedad C++. Como en el caso de las presentaciones sociales, esta presentacin no se reduce a indicar el nombre; tambin puede sealarse algunas caractersticas o atributos de la entidad. Naturalmente estos atributos no pueden ser los mismos en todos los casos (los objetos no tienen los mismos que las funciones) aunque desde luego todos tienen un identificador.

3 Atributos Todas las declaraciones de entidades contienen un identificador asociado que se utiliza para acceder al objeto. Puede ser un identificador simple (nombre), o una expresin compleja que represente unvocamente al objeto ( 2.1.1 ). Cualquier intento de utilizar una declaracin sin un nombre es un error, aunque el nombre no tiene que responder necesariamente a un objeto o funcin. Ejemplo: extern int; char*; char* cptr; class C; typedef unsigned int UINT; // // // // // Error!! Error!! Ok. cptr nombre de puntero Ok. C nombre de clase Ok. UINT alias para un tipo conocido

Adems del identificador, las declaraciones de funciones pueden incluir ciertos atributos: inline ( 4.11.2a); virtual ( 4.11.8a) y explicit ( 4.11.2d1).

Por su parte, las declaraciones de objetos-valor pueden incluir atributos de diversos tipos [1]: Relativos al tipo de objeto: Su mero conocimiento ya anuncia al compilador algunas propiedades y operaciones que se pueden ejecutar con el objeto ( 2.1 ). Entre otros puede incluir los siguientes: char, wchar_t, bool, short, int, long, signed, unsigned, float, do uble, void. Relativos al tipo de almacenamiento. Determina el sitio en que se guarda el objeto y su duracin ( 2.1.3 ). Puede ser alguno de los siguientes: auto, register, static, extern y mutable. Relativos al tipo de enlazado: extern. Relativos a propiedades diversas: friend; typedef; asm. Relativo a su variabilidad (capacidad de que el "valor" pueda o no cambiar a lo largo del programa): const.

Nota: observe que los atributos identificador y almacenamiento son distintos, lo que permite establecer una interesante disquisicin respecto a si un mismo objeto. Por ejemplo una variable, puede estar referenciado por dos identificadores distintos (que se refieren a la misma regin de memoria). En la mayora de lenguajes de programacin esta distincin, entre identificador y almacenamiento, est perfectamente establecida, y suelen proporcionar mecanismos sintcticos para que dos identificadores puedan referirse al mismo almacenamiento.

4.1.2 Declaraciones y definiciones


1 Sinopsis Utilizando un lxico formalista, podemos decir que una declaracin es una sentencia que introduce un nombre en una unidad de compilacin ( 1.4.2) dndole existencia semntica. Esto de la "existencia semntica" es una forma elegante de decir que a partir de ah el compilador sabe que "cosa" es (representa) ese nombre. La forma de darle existencia semntica a las entidades es declararlos (algo as como "presentarlos" formalmente en el cdigo). Por ejemplo, si declaramos una variable x o una funcin func, a partir de ah el compilador sabe que x es una variable de tal tipo, y que func es una funcin de caractersticas cuales. El punto importante a resaltar aqu es que cada declaracin asocia un nombre con un tipo de dato, lo que en C++ (una sociedad muy clasista 2.2) es importante, ya que el conocimiento del "tipo" que corresponde a un identificador, proporciona al compilador mucha informacin sobre la entidad representada por este (en muchas ocasiones "casi" toda la informacin necesaria ). En especial el compilador dispone de una amplia informacin acerca del uso de los tipos bsicos; que operaciones son permitidas, y que significado tienen estas operaciones. No olvidar que una declaracin no hace nada ms que esto. Es decir, no aade ninguna otra informacin distinta de relacionar una etiqueta con un tipo. Posteriormente, cuando esta etiqueta est asociada con una entidad concreta (con una zona de memoria), las operaciones permitidas se realizarn sobre esta entidad. Recordemos que la entidad puede ser un objeto-dato o un algoritmo (una funcin).

1.1 La declaracin se completa con la definicin. En esta fase se concreta la creacin de la

entidad (donde y cuando). Si es un objeto-dato se le asigna memoria fsica y posiblemente se inicializa. Ejemplo: int x = 3;. Si es un algoritmo (funcin) se establece su cdigo. En muchos casos la declaracin y definicin se realiza en la misma sentencia. En otros casos la declaracin mantiene su sentido original de ser una simple exposicin de un tipo de entidad con un nombre y posiblemente algn atributo adicional ( 4.1.1); en este caso la declaracin se denomina tambin referencia. Como puede verse, las declaraciones pueden definir y/o referenciar. Cualquier declaracin que adems reserve almacenamiento a un objeto o funcin es una definicin. As pues, el concepto definicin implica una iniciacin del objeto (en el sentido de que empieza a tener existencia fsica al asignrsele espacio en memoria). En lo sucesivo, para evitar ambigedades, utilizaremos declaracin en el sentido referenciar, y definicincuando se trata de asignar memoria fsica y posiblemente inicializar esta con valores determinados. En estas cuestiones es muy importante mantener claras las diferencias conceptuales y semnticas, en especial cuando los objetos son instancias de clases:

1.2 Declaracin: Simplemente asocia un identificador con un tipo (existencia semntica). La declaracin de una funcin se denomina prototipo ( 4.4.1). La gramtica C++ exige que la declaracin de una entidad se indique primero su tipo y despus el identificador con el que se la conocer en adelante. Ejemplos: extern int x; class C; int func(int x, char c);

// prototipo

Observe que la gramtica C++ permite realizar varias declaraciones en una sola sentencia separando con comas los identificadores: int x, y, z; C c1, c2, c3; Pero hay que prestar atencin a este tipo de sentencias porque pueden deparar sorpresas: int x, y, z; C* c1, c2, c3; C. // Ok! x, y, z son tipo int. // Atencin: c1 es tipo C*, mientras que c2 y c3 son tipo

Despus de la declaracin es poco lo que puede hacer el compilador con una etiqueta, ya que solo conoce el "tipo" de objeto que representa. Sin embargo, son posibles aquellos usos para los que basta con esta informacin. Ejemplo: struct E1; struct E2* pe2; E1* ep1; // declara que E1 es tipo struct // declara que pe2 es tipo E2* (puntero-a-struct-E2) // declara que pe1 es tipo E1* (puntero-a-struct-E1)

Este tipo de declaraciones se denominan adelantadas (en el sentido que no estn acompaadas por una definicin adecuada). Las entidades en esta situacin (en la que el compilador solo tiene

conocimiento del tipo), se denominan tipos incompletos ("Incompletely defined object type"); son las clases declaradas y no definidas, y las matrices de tipos incompletos o de tamao indefinido. Ejemplo: class C; char m1[ ]; C matriz[5]; // clase declarada pero no definida // matriz de tamao indefinido // matriz de tipos incompletos

Nota: para justificar que tiene unas caractersticas de tipo que podramos denominar "restringidas", el Estndar C++ (3.9) establece que el tipo void ( 2.2.1) es tambin un tipo incompleto (que no podr nunca llegar a ser completo).

Salvo en las contadas ocasiones en que no se requiere conocer el tamao del objeto, los tipos incompletos no pueden ser utilizados en la definicin de otros tipos, aunque s en su declaracin tambin incompleta-. Ejemplo: extern C* cptr; typedef int UNDA[]; UNDA* aptr; class D { UNDA** apptr; ... }; // puntero a tipo incompleto // matriz incompleta // puntero a tipo incompleto // Error: puntero a tipo incompleto // en definicin

En los casos en que no es necesario conocer el tamao del objeto incompletamente declarado, s es posible utilizarlos en la definicin de otras entidades. Esto ocurre tpicamente cuando la definicin solo contiene punteros y referencias al objeto incompleto, ya que en ambos casos, el tamao siempre es el mismo. Por ejemplo, sera vlido el siguiente trozo de cdigo: class A: /* Clase declarada pero no definida aqu la suponemos definida en otra unidad de compilacin */

class B { public: A* aptr; void foo (const A& a); ... }

1.3 Iniciacin: asigna memoria fsica al objeto (existencia fsica). Si no se produce una inmediata asignacin de valores determinados, la zona asignada puede contener basura. Ejemplo: int* ptr; int x;

1.4 Definicin: asocia un identificador con un tipo y le asigna espacio en memoria (declaracin + iniciacin). Observe que despus de la definicin, el objeto no tiene porqu estar inicializado. Es decir, si es un objeto-dato, el espacio asignado puede contener basura. En el caso de funciones, la definicin se realiza cuando se establece el cuerpo de la funcin. En el caso de clases, cuando se describen cuales sern sus propiedades y mtodos. Ejemplo:

int x; int func(int x, char c) { return (x + c) } class C { int x; char c; };

Adelantemos aqu que en C++ existe la denominada regla de una sola definicin ODR ("One Definition Rule") segn la cual, cualquier nombre puede ser declarado varias veces en cada unidad de compilacin (con la condicin de que estas declaraciones sean idnticas), pero solo puede definirse una vez . Al tratar de los constructores y destructores ( 4.11.2d) veremos que en C++ es muy importante la correcta creacin e inicializacin de los objetos, por lo que en el caso de los tipos complejos ( 2.2) la creacin e inicializacin estn indisolublemente unidas, y el lenguaje garantiza que al crearse un objeto es inicializado adecuadamente.

1.5 Inicializacin: asignar valores concretos al objeto (existencia utilizable); a partir de aqu, el espacio de memoria contiene datos correctos. Ejemplo: x = 5; int* ptr = &x; int y = y; C c; C d = { 15, 'z' }; // // // // // inicia x con el valor 5 inicia ptr con la direccin de x inicia y con su propio valor indefinido Valores por defecto asignados por el constructor Valores asignados de forma explcita

1.6 Destruccin: en adelante el identificador no es reconocido y el espacio de memoria es desasignado; puede volver a ser utilizado por otros objetos. Sus valores actuales pueden permanecer, pero sern basura para el prximo objeto que ocupe dicho espacio de memoria. Ejemplo: delete c;

1.7 De acuerdo con lo anterior, puede considerarse que la secuencia vital de un objeto utilizable por el programa contiene las siguientes fases: Declarar Iniciar Inicializar Destruir Relacionar un identificador (nombre) con un tipo. Reservar almacenamiento. Asignarle valores. Desasignacin semntica y fsica

Aunque existen circunstancias en las que los tres primeros estadios del objeto ocurren por separado, en ocasiones el compilador los realiza simultneamente. Sobre todo cuando tiene suficiente informacin para ello. En ocasiones es conveniente y necesaria esta simultaneidad (caso de las constantes); en otras trata de evitarse.

2 Al llegar a este punto hay que hacer una matizacin importante: Cuando en un programa C++

se encuentra una expresin del tipo: int n;tcnicamente hablando se trata solo de una declaracin. Sin embargo, el compilador ya tiene toda la informacin necesaria (en este caso) y le asigna un espacio de memoria (momentneamente puede estar lleno de basura). Por esta razn, a veces se dice que una expresin como la anterior es una definicin. En estos casos, la nica forma de asegurarse que el compilador interpreta la sentencia en sus trminos exactos (solo declaracin), es aadiendo el especificador extern. Ejemplo: extern int n; Esto garantiza que el compilador sepa que es solo una declaracin, y que la definicin (y el almacenamiento) est en algn otro sitio. Ntese que lo anterior (conocer toda la informacin con solo la declaracin) solo ocurre con las declaraciones de variables, no as con las funciones. En una declaracin de funcin (lo que denominamos un prototipo) de la forma: int funcion (char letra, int cantidad, long distancia); el compilador no puede hacer gran cosa (aparte de una verificacin esttica de tipos), ya que falta el cuerpo (definicin) de la funcin. De hecho, en la declaracin de cualquier funcin puede suponerse que est implcito el especificador extern ( 4.1.8d). Ms detalles y ejemplos: ( Declaraciones y definiciones)

3 Regla de una sola definicin Esta regla, conocida tambin por su acrnimo ingls ODR, establece que en cada programa, especialmente si es multifichero, puede haber muchas referencias al mismo identificador, pero solo se permite una definicin para cada identificador en cada espacio de nombres ( 4.1.11). Las entidades que se pueden declarar incluyen: Variables Funciones explcitas y genricas Clases explcitas y genricas y sus miembros Tipos Etiqueta estructura, unin y enumeracin Miembros de Estructuras Miembros de Uniones Matrices de otros tipos Constantes de Enumeracin Etiquetas Macros de preproceso

Observe que si nos referimos al espacio global del programa, la regla ODR conduce a que en todo el programa solo puede existir una definicin de cualquiera de las entidades antes enunciadas. Dentro de un mismo fichero pueden existir mltiples typedef ( 3.2.1a) o macro definiciones (#define 4.9.10b), siempre que la definicin resultante sea la misma, lo que es conocido como redefinicin benigna ("benign redefinition"). De forma general puede afirmarse que un identificador no puede utilizarse en un programa antes del punto del cdigo fuente en que es declarado [1]. Las excepciones a esta regla, conocidas

como referencias adelantadas ( 4.11.4a), son llamadas a funciones; etiquetas de clases; estructuras, o uniones no declaradas. A pesar de lo anterior, el lector habr observado que es frecuente la prctica de incluir definiciones en ficheros de cabecera, digamos p.e. <cabecera.h> y que ms tarde pueden aparecer sentencias del tipo #include <cabecera.h> en varios fuentes del mismo programa, lo que conducira a pensar que se contraviene la regla [6]. La razn de que en estos casos no se produzcan errores, es que esta regla no debe tomarse al pi de la letra: En realidad el compilador acepta la aparicin en el cdigo de ms de una definicin de una entidad, y las toma como imgenes de una sola definicin, siempre que se cumplan las siguientes condiciones: Las definiciones aparezcan en distintas unidades de compilacin. Resulten idnticas token a token para el "parser" ( 1.4). El significado de los tokens sea idntico en todas estas unidades de compilacin (no ocurra, por ejemplo, que un smbolo tenga un significado en un mdulo y otro distinto en el siguiente debido a un typedef).

4 Declaraciones En la prctica una declaracin es una lista de nombres (identificadores) que comienzan con un especificador de tipo de almacenamiento (que es opcional), seguido de especificadores de tipo y otros modificadores. Los identificadores estn separados por comas y toda la lista terminada en punto y coma ;. Una declaracin de variables puede tener el siguiente aspecto: tipo-de-dato var1 <=inic1>, var2 <=inic2>, ...; donde var1, var2,... es cualquier secuencia de identificadores distintos con iniciadores <=inicX> opcionales. Cada una de las variables es declarada del tipo sealado por tipo-de-dato. Por ejemplo: int x = 1, y = 2, z; Esta declaracin [2] crea tres variables de tipo int: x, y, y z, y las inicia a los valores 1 y 2, respectivamente (z queda sin definir).

En los ejemplos de declaraciones que siguen puede verse que los tipos de los identificadores (en todos los casos es el mismo: nomb y cont) se deducen de los declaradores (en negrita). Declaracin tipoX nomb; tipoX nomb[]; tipoX nomb[3]; tipo implcito de "nomb" // tipoX // matriz (abierta)de tipoX // matriz de tres elementos tipoX // nomb[0], nomb[1] y nomb[2]) tipoX* nomb; // Puntero-a-tipoX tipoX* nomb[]; // Matriz de punteros-a-tipoX tipoX *(nomb[]); // equivalente al anterior tipoX (*nomb)[]; // -Puntero a matriz de tipoX []; tipoX &nomb; // Referencia a tipoX Ejemplo de uso int cont; int cont[]; int cont[3]; int int int int *cont; *cont[]; *(cont[]); (*cont)

int &cont;

tipoX nomb(); tipoX* nomb(); tipoX *(nomb()); tipoX (*nomb)();

// // // //

Funcin devolviendo tipoX Funcin devolviendo puntero-a-tipoX equivalente al anterior -Puntero a funcin devolviendo tipoX

int int int int

cont(); *cont(); *(cont()); (*cont)();

Nota: observe la necesidad de parntesis en (*nomb)[] y (*nomb)(). Es as porque en ambos, la precedencia ( E4.9.0a) del declarador de matrices [ ] y del declarador de funciones ( ), es mayor que el declarador de puntero *. En cambio, el parntesis en *(nomb[]) es opcional.

5 Definiciones Se tiene una definicin cuando el compilador tiene informacin suficiente para construir en memoria una imagen de la entidad. Podemos suponer que la definicin es una reserva o asignacin de espacio en un sitio concreto de memoria. int x; char ch; long z; int dias[7]; struct S { int a; int b; }; char* ptr; float power2(float n) { return n*n; }

La definicin de una entidad C++ puede ser un proceso bastante complejo. En especial cuando se trata de estructuras o clases. Es frecuente que en estos casos, el proceso se considere descompuesto en dos fases: una primera fase es la mera declaracin, y contiene una imagen o resumen del cuerpo de la clase con las declaraciones de sus propiedades y los prototipos de sus funciones-miembro. La definicin propiamente dicha, se realiza en una segunda fase, denominada de implementacin, en la que se precisan todos los detalles, incluyendo las definiciones de todas las funciones-miembro, posible lista de iniciadores ( 4.11.2d3) Etc. El subconjunto de la declaracin, que contiene solo referencias a las propiedades y mtodos pblicos, se conoce como interfaz de la clase. Se supone que la interfaz contiene toda la informacin de debe conocer el usuario de la clase para poder utilizarla. El resto de miembros privados y protegidos solo conciernen al implementador de la clase.

6 Iniciar Se ha apuntado que iniciar es el hecho de dar valores concretos, y correctos, a la imagen en memoria de la entidad. El vocablo "iniciar" se utiliza solo con variables y constantes [5], dado que las funciones no pueden ser "iniciadas" (su proceso de creacin concluye con la definicin). Cuando se inicia un objeto, debe estar ya declarado y definido (aunque todos los pasos puedan estar implcitos en la misma sentencia). Es decir, antes de iniciar una constante o variable, el compilador debe conocer el tipo a que pertenece el identificador y disponer del espacio correspondiente en memoria. Lo usual es que este espacio est previamente ocupado por valores sin sentido (basura).

En general, la inicializacin se realiza mediante asignaciones, que pueden realizarse en el momento de la declaracin o despus, pero existen posibilidades sintcticas especiales para algunos tipos. Por ejemplo: las matrices ( 4.3.1), estructuras ( 4.5.2), uniones ( 4.6), y las instancias de clases (objetos). En particular estas ltimas disponen de funciones especiales encargadas de estos menesteres: los constructores ( 4.11.2d3). En los siguientes epgrafes se exponen algunas reglas y consideraciones sobre el asunto.

7 Reglas de inicio 7.1 El Estndar establece que dentro de cada unidad de compilacin, la inicializacin de los objetos se realizar en el mismo orden de su definicin [7].

7.2 Si un identificador tiene mbito de bloque y especificacin de enlazado externo o interno, la declaracin no puede contener ninguna inicializacin (debe ser una mera referencia). Ejemplo: ... { extern long peso = 1000; extern long peso; } ... Nota: una sentencia como L.1 puede no producir error porque el compilador sencillamente ignora la clusula extern. Recuerde que una declaracin con inicializador es siempre una definicin. // L.1 Error // L.2 correcto

7.3 Recuerde que fuera de los bloques de funciones o clases, en l mbito global de fichero, no puede existir ningn tipo de sentencia distinta de definiciones o declaraciones. Por ejemplo, considere el siguiente programa: #include <iostream.h> int a; // L.2 Ok. declaracin a = 13; // Error: Asignacin no permitida aqu int b = 23; // Ok. definicin int c = b; // Ok. definicin cout << "c = " << c << endl; // Error: sentencia no permitida aqu int main() { cout << "a a = 13; cout << "a int d; cout << "d d = 33; cout << "d } // = " << a // = " << a // = " << d // = " << d ===================================== << endl; // Ok. sentencia permitida Ok. Asignacin permtida aqu << endl; M.4 Ok. declaracin << " (Basura)" << endl; Ok. Inicializacin << endl;

Salida despus de eliminadas las sentencias errneas: a = 0

a = 13 d = 5570560 (Basura) d = 33

Tenga en cuenta que las variables declaradas (y no inicializadas) en el espacio global, o en un subespacio de nombres, son inicializadas por defecto. Por ejemplo, la sentencia L.2 del ejemplo anterior equivale a: int a = 0; lo que explica la primera salida. En cambio esto no ocurre con las variables locales ( 4.1.8a) o creadas en la zona de almacenamiento persistente ( 1.3.2), as que la variable d declarada en M.4 no es inicializada por defecto y contiene basura.

7.4 Las variables escalares pueden inicializarse en el mismo punto de su declaracin siguiendo el nombre de la variable con el signo igual y una expresin (en otras palabras: mediante una asignacin utilizando una expresin como Rvalue). Ejemplo: int x = 1; char simplecomilla = '\''; long msdia = 1000L * 60L * 60L * 24L ; // milisegundos del da

Si un objeto tiene duracin automtica y no es inicializado, su contenido es indeterminado (puede ser simplemente basura). En estas, y en las variables de registro, el iniciador no est restringido a una constante. Puede ser cualquier expresin que implique valores previamente definidos, incluso llamadas a funciones. Por ejemplo: int binsearch(int x, int v[], int n) { iny low = 0; int high = n-1; int mid; ... }

7.6 Para variables externas y estticas la inicializacin ocurre conceptualmente una sola vez antes que el programa comience su ejecucin. Si no son inicializadas explcitamente, la inicializacin ocurre antes que cualquier otra en el programa, adoptndose por defecto los valores que siguientes: o Cero si es de tipo aritmtico o Nulo si es un puntero Si son inicializadas mediante expresiones constantes, esta inicializacin ocurre antes que la de los objetos automticos . Los inicializadores de objetos estticos pueden ser cualquier expresin que incluya constantes y variables, o funciones que hayan sido declaradas previamente.

7.7 Los iniciadores de una lista de inicio para una matriz deben ser constantes o expresiones que

se reduzcan a una constante. En el ejemplo que sigue, todas las expresiones son correctas, y las cinco matrices resultan de contenidos idnticos: int char char char char char char ... char x = 97; ch = 'a'; m1[] = {"Hola"}; m2[4] = {'H','o','l','a','\0'}; m3[4] = {'H','o','l',ch,'\0'}; m4[4] = {'H','o','l',f(97),'\0'}; m5[4] = {'H','o','l',f(x),'\0'}; f(int x){ return (char)x; }

El compilador C++Builder permite declaraciones posteriores de variables externas [4], tales como matrices, estructuras y uniones, de forma que se aada informacin a la contenida en la declaracin previa. Ejemplo: extern int a[]; // L1: struct mystruct; // L2: ... int a[3] = {1, 2, 3}; // se struct mystruct { int i, j; }; // se no se especifica tamao (matriz abierta) no especifica miembros (decl. anticipada) especifica tamao y se inicia aade declaracin de miembros

Obsrvese que la expresin de L1 es una declaracin de a como variable externa, la lnea L2 es en cambio una declaracin anticipada en el sentido indicado en 4.5.1e. Lo nico que hace esta sentencia es declarar mystruct como de mbito global al fichero. Se trata pues de matices distintos en ambas declaraciones.

7.8 Inicio de matrices, estructuras y uniones Las estructuras y matrices pueden inicializarse (incluso en el mismo punto de su declaracin), con una lista de iniciadores entre corchetes { }separados por comas, uno para cada miembro de la matriz o estructura. Por ejemplo: int dias[7] = { 1, 1, 1, 1, 1, 1, 1 } Las reglas que siguen se aplican a la inicializacin de matrices de caracteres normales y anchos ( 3.2.3):

7.8.1 Puede iniciarse una matriz de caracteres con una cadena literal, opcionalmente entre corchetes. Cada carcter de la cadena, incluyendo el terminador nulo (incluido automticamente), inicializa elementos sucesivos del array. Por ejemplo: char nomb[] = { "Jorge" }; inicia una matriz de seis elementos, que son:

nomb[0]=='J', nomb[1]=='o', ... nomb[6]== 0. Equivale a: char nomb[] = {'J','o','r','g','e','\0'};

7.8.2 Puede iniciarse una matriz de caracteres anchos (compatible con wchar_t) utilizando una cadena de caracteres anchos, opcionalmente entre corchetes. Como en el caso de caracteres normales, los cdigos de la cadena alfanumrica ancha inician elementos sucesivos de la matriz.

7.8.3 La inicializacin de estructuras y uniones se detalla en los apartados correspondientes ( 4.5.2).

8 Definicin provisional En contra de lo que ocurre en C, en C++ no existe el concepto de declaracin provisional [3]. Una declaracin de dato externo sin un especificador de tipo de almacenamiento, es tomado siempre como una definicin, por lo que cualquier inicializacin posterior dar lugar a un error de "Declaracin mltiple". Por ejemplo: int int int int int int x; x; y; y = 4; z = 5; z = 6; // declara x // Error: "Mltiple declaracin // declara y // Error: "Multiple declaracin // Legal: z declarado e iniciado // Error: "Mltiple declaracin

de x" de y" a 5 de z"

4.1.3 mbito
1 Sinopsis Aunque los iremos tratando con ms detalle, permitidme una breve puesta en escena de tres conceptos que son claves para entender estas cuestiones: mbito, visibilidad y vida. Cada identificador es introducido en el cdigo mediante una declaracin. A partir de este punto de declaracin , es conocido por el compilador en una regin que llamaremos mbito; es la zona en que la declaracin tiene efecto. Dentro de este mbito no puede existir otra declaracin con el mismo identificador [3]. Nota: el mbito corresponde con una zona del fuente englobada entre llaves { }, una lista de parmetros en una funcin o plantilla, o el espacio de una unidad de compilacin no incluido en cualquier otro mbito.

Dentro del mbito existen zonas en las que el identificador es visible, es decir, puede ser utilizado para designar a la misma entidad sin necesidad de un cualificador . En la prctica ocurre que cada identificador solo es visible en algunas regiones de su mbito (que pueden ser discontinuas). El conjunto de estas regiones es su rea de visibilidad ("scope"). La razn por la que un identificador deja de ser visible dentro de su mbito es que sea eclipsado por otra declaracin explcita que utiliza el mismo nombre. La nueva declaracin puede ocurrir en un bloque de cdigo anidado (en el mismo no es posible la nueva declaracin), o en una clase derivada. Nota: para determinar el "scope" de un identificador es usual referirse al mbito potencial de su declaracin. En principio su "scope" es el de su potencial, a menos que este contenga otra declaracin del mismo nombre, en cuyo caso, el mbito potencial de la nueva declaracin oculta o "eclipsa" parte del potencial del primero. En ocasiones el identificador es totalmente inaccesible en estas zonas "de sombra". En otras puede ser accedido mediante un cualificador adecuado.

Como se deduce de lo anterior, las propiedades mbito, scope y visibilidad, son atributos de un identificador en el cdigo [2]. Observe que las dos primeras se refieren a una zona del cdigo (un conjunto de sentencias), mientras que la visibilidad es una propiedad puntual; el estado visible/invisible del objeto puede cambiar en cada lnea dentro del mbito. El conjunto de todas en las que est visible constituye su rea de visibilidad o "scope". Ejemplo: int x; ... void main () { x = 10; int x = 11; int& x1 = x; cout << x; cout << ::x; { x = 12; cout << x; cout << ::x; cout << x1; } cout << x; } // declaracin de x // punto de declaracin de x // // // // // // // // // Ok x est en "scope" (1 variable x) nueva declaracin de x (2 variables x) referencia a la x anterior -> 11 -> 10 observe el nombre cualificado nueva declaracin de x (3 variables x) -> 12 -> 10 -> 11 (nico acceso a este x) (2 variables x) (0 variables)

// -> 11 //

La vida ("Lifetime") es un atributo de tiempo de ejecucin ("runtime"). Es el tiempo en que una entidad se mantiene en memoria. Es decir, desde que es creado hasta que es destruido ( 4.1.5). Conviene recapitular que en el programa existen dos entidades distintas: un identificador, o lo que es lo mismo, un nombre conocido por el compilador (visible o invisible momentneamente) y una zona de memoria donde est la entidad que referencia la etiqueta (el Rvalue 2.1.5); que el

identificador tiene su propio mbito y visibilidad, y que la nica forma que tiene el compilador para acceder al objeto es mediante su identificador (o mediante el identificador de un objeto que lo seale -un puntero-). En estas circunstancias, al menos tericamente, pueden suponerse diversas situaciones:

1.1 El identificador est en mbito (vivo) y en "scope" (visible); la zona de memoria contiene los datos correctos. El objeto es accesible por el programa y las cosas funcionan correctamente. Por ejemplo: int x = 3, j = 1; x = j +10 cout << "x = " << x << endl;

1.2 El identificador est en mbito (existe y est vivo) pero fuera de "scope"; el almacenamiento sigue intacto. Para todos los efectos es como si los datos no existieran; puede que ms tarde vuelva a estar en mbito (vuelva a ser visible). Es la tpica situacin en que un identificador es ocultado (eclipsado o tapado) momentneamente por otro del mismo nombre en un bloque ms profundo. Por ejemplo: int x = 3, j; for (j = 0; j>10; j++) { int x = 0; // oculta x anterior mientras dure el bucle ... } cout << x << endl; // la x original vuelve a ser visible

1.3 El identificador est en mbito, vivo y visible, pero su zona de memoria est ocupada por otros valores no esperados. El nombre sigue siendo utilizable por el programa, pero al acceder al objeto recibimos basura. Es el caso de identificadores, generalmente punteros, descolgados ("dangling pointers"). Esta es una situacin anmala, pero puede presentarse por mltiples causas. Por ejemplo, un objeto ha sido eliminado de memoria mientras que existen referencias vlidas al mismo (punteros). Tambin porque no hemos inicializado adecuadamente la variable, o porque algn puntero descontrolado ha metido datos en el sitio inadecuado. Los resultados son impredecibles. Por ejemplo, al realizar una operacin con ese objeto recibimos un error de "runtime".

1.4 El identificador est fuera de mbito (muerto y por supuesto invisible), el compilador no puede hacer ms uso de l, pero el programa no ha rehusado la zona de memoria correspondiente, no la ha vuelto a declarar zona libre. Por ejemplo, porque el programador ha olvidndose el destructor de una clase o usar el operador delete antes de salir de una funcin. El resultado es que la memoria sigue conservando los datos intilmente. Es la tpica situacin de prdida de memoria por el programa. Es un error de programacin tpico en sistemas que no disponen de un recolector automtico de basura, como es el caso de C++. Tambin la causa de que aparezcan lenguajes como Java, que s disponen de esta caracterstica.

2 Clases de mbito

En C++ hay siete categoras de mbitos: De sentencia; de bloque (o local); de funcin; de prototipo de funcin; de fichero; de clase y deespacio de nombres. El mbito depende de como y donde es declarado el identificador. Aparte del mbito de Clase (que no existe en C) las reglas de mbito para C++ son las mismas que en C, con la salvedad que, a diferencia de este, C++ permite que la declaracin de datos y funciones aparezca en cualquier sitio en que pueda aparecer una sentencia. Esta especial flexibilidad implica que deba prestarse especial atencin cuando se interpreten cuestiones tales como "punto de declaracin" y enclosing scope. Por ejemplo, las siguientes declaraciones son correctas en C++ pero no en C. void main(void) { int i = 100; cout << "Es el numero " << i << endl; char ch = 'A'; cout << "Es la letra " << ch << endl; } Para ser compilado como C tendran que haberse declarado las variables antes que ninguna ejecucin de funcin. Por ejemplo: void main(void) { int i = 100; char ch = 'A'; cout << "Es el numero " << i << endl; cout << "Es la letra " << ch << endl; }

2.1 mbito de Sentencia C++ soporta declaraciones en expresiones condicionales; pueden declararse variables dentro de las expresiones de las sentencias for, if, while yswitch; entonces el mbito de las variables es el de la sentencia. En el caso de if el mbito incluye tambin el bloque else. Ejemplo: ... for (j = 0; j>10; j++) { // comienza el mbito de j int x = 0; // comienza el mbito de x ... } // termina el mbito de j x (ver nota) ... Nota: C++Builder incluye la opcin de la opcin -Vd de compilacin que permite modificar el mbito de las variables declaradas dentro de las sentencias for ( 4.10.3).

2.2 mbito de Bloque El mbito de un identificador con mbito local (o de bloque), empieza en el punto de declaracin y termina al final del bloque que contiene la declaracin (el denominado bloque contenedor). Ejemplo: ...

{ ... char c = 'c'; int x = 0; ... } ... // comienza el mbito de c // comienza el mbito de x // termina el mbito de c x

El mbito de los parmetros declarados en la definicin de una funcin es el del bloque que define dicha funcin. Ejemplo: ... int func (int x, int y) { ... int y = 12; return (x + y); } ...

// comienza el mbito de x y // Error!! declaracin duplicada // termina el mbito de x y

2.3 mbito de Funcin Los nicos identificadores que tienen mbito de funcin son las etiquetas de goto ( 4.10.1), razn por la cual sus nombres deben ser nicos en la funcin. Su mbito es el de la funcin que las contiene, de forma que pueden ser utilizados por las sentencias goto en cualquier punto de la funcin en que se han declarado. Los identificadores de funcin tienen enlazado externo ( 1.4.4), lo que significa que pertenecen al mbito global (el mismo para todas). Es decir, pueden ser referenciadas desde cualquier punto del fichero, incluso desde otras funciones, incluyendo main(), o desde ellas mismas (recursin), pero el bloque de cdigo que engloba el cuerpo de cada funcin, incluyendo sus variables, es un espacio oculto, no puede ser accedido directamente desde su exterior. Por esta razn no es posible, por ejemplo, realizar un salto goto a una etiqueta en otra funcin. La nica manera de acceder a una funcin es mediante una llamada a la misma siguiendo el formato especfico definido en su prototipo. El nico valor que se puede manejar directamente es el que devuelve y an as, no es el valor original, sino una copia modelada de este (ver la sentencia return 4.4.7). Los nombres contenidos en la lista de parmetros formales de una funcin pertenecen al mbito del bloque ms externo de la funcin (el que define el cuerpo de la funcin). Una consecuencia de que todas las funciones comparten el mismo mbito global es que no puedan declararse funciones dentro de funciones. Nota: las cosas eran como se han descrito hasta la introduccin en el lenguaje del mecanismo de espacio de nombres ( 4.1.11), momento desde el cual, C++ permite la existencia de funciones fuera del espacio global [1]. Adems, las clases funcionan como autnticos subespacios de nombres ( 4.1.11c1), por lo que tambin pueden declararse funciones dentro de ellas (las funciones-miembro) que no pertenecen por tanto al espacio global.

2.4 mbito de Prototipo

Los nombres declarados en la lista de parmetros de un prototipo de funcin (que no sea parte de una declaracin) tienen mbito reducido al prototipo. En realidad estos nombres solo son utilizados para el posible anuncio por el compilador de errores o advertencias sobre el prototipo que se declara.

2.5 mbito de Fichero Los identificadores con mbito de fichero, son llamados tambin globales o externos. Son declarados fuera de cualquier bloque, clase o funcin. Su mbito abarca desde el punto de declaracin hasta el final del fichero (por esta razn se suelen declarar al principio del fichero, justo despus de las directivas # de preproceso).

2.6 mbito de Clase Una clase ( 4.11) es una coleccin de elementos (miembros) junto con las operaciones que se realizan con ellos. El trmino mbito de clase se aplica a los nombres de los miembros de una clase particular. Las clases y sus miembros tienen reglas de acceso y de mbito muy especiales.

El nombre N de un miembro de una clase C tiene mbito local a C, y puede ser utilizado solo en las siguientes situaciones: En funciones miembro (mtodos) de C. En expresiones tales como c.N, donde c es un objeto de C (Selector directo de miembro 4.9.16) En expresiones tales como cptr->N, donde cptr es un puntero a una instancia de C (Selector indirecto de miembro 4.9.16) En expresiones tales como C::N o D::N, donde D es una clase derivada de C ( En referencias anticipadas de miembros dentro de la clase.

).

Recuerde que los nombres de funciones declaradas amigas ( friend 4.11.2a) de C no son miembros de C; sus nombres simplemente tienen mbito de la clase C.

2.7 mbito de espacio de nombres El espacio de nombre es el mbito en el que un identificador debe ser nico. A este respecto, C usa cuatro clases distintas de identificadores: Nombres de etiquetas goto. Deben ser nicas dentro de la funcin en que se han declarado (el goto tiene mbito de funcin). Nombres estructuras, uniones y enumeraciones. Deben ser nicas dentro del bloque en que se han definido. Las etiquetas definidas fuera de cualquier funcin deben ser nicas (ya que son globales al fichero). Nombres de miembros de estructuras y uniones. Deben ser nicos dentro de la estructura o unin en que se han definido. No existe restriccin en el tipo de miembros del mismo nombre en diferentes estructuras.

Variables, funciones, typedef y enumeradores. Deben ser nicos dentro del mbito en que han sido definidos. Los identificadores declarados externos deben ser nicos entre las variables declaradas externas.

C++ tiene una palabra clave: namespace ( 4.1.11), que es en realidad un recurso para manejar los identificadores. Permite dividir el espacio total de nombres en regiones distintas e independientes respecto a los identificadores. Los objetos definidos en el subespacio raz tienen mbito de todo el programa (de la aplicacin) siempre que se hayan definido como extern en el resto de los mdulos. A su vez los compiladores utilizan una serie de variables y tipos globales a la aplicacin cuyos nombres predefinidos que son incluidas automticamente en cualquier programa C++ para usos varios, como fechas, horas, etc ( 4.1.3a).

3 Ocultacin Un nombre puede ser ocultado por una declaracin explcita del mimo nombre en un bloque ms profundo o en una clase. Ejemplo: int x = 3, j; for (j = 0; j>10; j++) { int x = 0; // oculta al anterior ... } cout << x << endl; // la x original vuelve a ser visible

Los parmetros formales de las funciones ocultan cualquier otra variable o funcin externas del mismo nombre. Por ejemplo: int x, y; // espacio global func(double x, double y) { ... // x e y globales no son visibles aqu }

3.1 Acceso cualificado: El miembro oculto m de una clase CL es todava accesible utilizando el operador de acceso a mbito :: ( 4.9.19) con un nombre de clase:CL::m. Un nombre de mbito global (de fichero) oculto, puede ser todava referenciado utilizando el operador ::. Ejemplo: #include <iostream> using namespace std; int x = 1; // x-global int main() { // ============== cout << "1. x = " << x << endl; x = 2; // se refiere a x-global

cout << "2. x = " << int x = 4; for (int j = 0; j<1; int x = 3; cout << "3. x = " ::x = 5; } cout << "4. x = " << cout << "5. x = " << } Salida: 1. 2. 3. 4. 5. x x x x x = = = = = 1 2 3 4 5

x << endl; // Nueva x (x-de-main) oculta a la anterior j++) { // Nueva x (x-de-for) oculta a la anterior << x << endl; // se refiere a x-global x << endl; ::x << endl;

3.1a Un nombre de clase puede ser ocultado por el nombre de un objeto, funcin o enumerador declarado dentro de su mbito, con independencia del orden en que se hubiesen declarado los nombres. Aunque la clase oculta puede ser todava accesible precediendo su identificador con la palabra clave apropiada: class, estruct o union. Ejemplo: class C { .... }; int main() { int C; C c; class C c; } // ============= // Error clase C no definida (oculta por int C) // Ok. compila sin dificultad

4 Punto de declaracin A todos estos efectos, el punto de declaracin de un nombre x es inmediatamente despus de su declaracin completa, pero antes de su inicializador si es que existe alguno.

5 Acceso a entidades Cuando el compilador encuentra en el cdigo la utilizacin de un identificador, intenta relacionarlo con alguna declaracin previa de dicho nombre. Este proceso es conocido como bsqueda de nombre ("Name-lookup"). El proceso puede asociar ms de una declaracin con un nombre si este corresponde a una funcin (funciones sobrecargadas); en este caso, la seleccin de la definicin adecuada sigue al "name-lookup" en un proceso conocido como resolucin de sobrecarga. Ver en la hoja adjunta una somera descripcin del proceso ( Name-lookup).

4.1.3a Tipos y variables globales


1 Sinopsis Los compiladores utilizan una serie de variables y tipos globales de nombres predefinidos que (utilizando las cabeceras adecuadas), pueden ser incluidos en cualquier programa C++ para usos varios, como clculos de fechas, horas, etc.

2 Variables y tipos globales ms frecuentes En concreto, Borland C++ utiliza las siguientes [1]:

Etiqueta _8087

Descripcin Sintaxis: extern int _8087; Esta variable adopta un valor distinto de cero si la lgica de autodeteccin del mdulo inicial ( 1.5) detecta la existencia de un coprocesador de coma flotante.

_argc

Sintaxis: extern int _argc; Esta variable adopta el valor pasado al argumento argc de la funcin main ( 4.4.4).

_argv

Sintaxis: extern char **_argv; extern wchar_t ** _wargv; Esta variable adopta el valor pasado al argumento argv de la funcin main (ver el punto anterior ). _wargv es la versin Unicode.

_ctype

Sintaxis: extern char _ctype[]; Esta variable es una matriz que incluye informacin sobre atributos de los caracteres. Cada elemento de la matriz es un conjunto de bits describiendo determinadas caractersticas del carcter. La matriz es utilizada por determinadas funciones de la Librera Estndar, como isdigit(), isprint(), isalpha(), etc.

_daylight

Sintaxis: extern int _daylight; Este valor es utilizado por las funciones de la RTL relacionadas con la fecha y la hora, por ejemplo mktime ylocaltime. Se trata de un entero que informa a dichas funciones cuando deben tener en cuenta los

adelantos y retrasos correspondientes a los horarios de verano e invierno. Esta variable es inicializada a partir de los valores contenidos en la variable TZ ( 1.7.1); adopta un valor distinto de cero si el valor DST est especificado en TZ y 0 en caso contrario. Si TZ no existe o tiene un formato incorrecto, su valor se obtiene del SO. Ejemplo: cout << _dylight; // -> 1

Comentario: El sistema est en horario de verano, con una hora de adelanto sobre la que correspondera por su uso horario. _doserrno _environ errno Esta variable es utilizada para almacenar mensajes de error cuando fallan ciertas rutinas de Librera. Cuando ocurre un error esta variable adopta un valor que identifica el tipo de error ocurrido. En ocasiones errno y _doserrno son equivalentes. Otras veces errno no contiene el correspondiente cdigo de error del Sistema que es, por contra, almacenado en doserror. Finalmente, en otras ocasiones el cdigo es reflejado en errno y no en doserrno. Ejemplo para mostrar los errores del sistema: int i = 0; while(_sys_errlist[i++]) printf("%s\n", _sys_errlist[i]); return 0; _floatconvert _fmode Esta variable controla si la apertura de ficheros se realizar por defecto en modo binario o texto para las funciones de Librera Estndar fopen(), fdopen() y freopen() ( 5.5.2). En consecuencia puede adoptar dos valores que corresponden a dos constantes predefinidas: O_TEXT y O_BINARY en Borland C++, y _O_TEXT, _O_BINARY en MS Visual. Su valor puede ser establecido mediante una funcin de librera: setmode() en Borland C++, y _setmode() en MS Visual C++. _new_handler _osmajor _osminor

_osversion _sys_errlist _sys_nerr _threadid __throwExceptionName __throwFileName __throwLineNumber _timezone Sintaxis: extern long _timezone; Esta variable contiene la diferencia de tiempo en segundos entre la hora GMT y la hora local LST (local standard time). Es utilizada por funciones de hora/fecha y calculada por la funcin de Librera tzset(). En Win32 este valor es obtenido del Sistema Operativo. Ejemplo: cout << _timezone; // -> -3600

Comentario: El sistema est en un uso horario GMT +01:00 (meridiano de Madrid-Bruselas-Pars). _tzname Sintaxis: extern char* _tzname[2] Como puede verse, se trata de una matriz de punteros a carcter. que representan componentes de la variable de entorno TZ ( 1.7.1): _tzname[0] seala a una cadena de tres caracteres representando el nombre del uso horario. _tzname[1] seala a una cadena de tres caracteres con el nombre de la zona DST ("Daylight Daving Time"). Si este valor no existe, _tzame[1] seala a una cadena nula. En los sistemas Win32, estos valores se obtienen del SO. Ejemplo: cout << _tzname[0]; cout << _tzname[1]; // -> // -> PST PDT

Comentario: Resultados obtenidos compilando con MS Visual C++. _wtzname Sintaxis: extern wchar_t *const _wtzname[2] Esta variable se define como un puntero constante a carcter ( 4.2.1e). Es la versin de caracteres anchos ( 2.2.1a1) de la

anterior. _version tm Se trata de una estructura que define el tiempo. Es utilizada por diversas funciones de la STL que tienen que ver con la fecha y la hora: asctime, gmtime, localtime, mktime y strftime. Ms informacin en el captulo correspondiente de la Librera Estndar ( 5.5.1). Ver ejemplo ( 4.5.5c). clock_t Sintaxis: typedef long clock_t; Este tipo define el valor devuelto por la funcin clock() definida en <time.h>, que devuelve el tiempo de procesador transcurrido desde el comienzo de la invocacin del programa. Ms informacin en el captulo correspondiente de la Librera Estndar ( 5.5.1). Ejemplo ( 9.1).

Tema relacionado: Constantes manifiestas (

1.4.1a)

4.1.4 Visibilidad
1 Sinopsis La visibilidad de un identificador es la regin de cdigo fuente desde la que se puede legalmente acceder al objeto asociado al identificador. mbito y visibilidad coinciden generalmente, si bien pueden darse circunstancias en que un objeto puede aparecer oculto (invisible) temporalmente debido a la presencia de un identificador duplicado. El objeto existe, pero el identificador original no puede ser utilizado para accederlo hasta que el identificador duplicado es terminado. Nota: la visibilidad no puede exceder al mbito, pero este puede exceder a la visibilidad. 2 Lo sealado en la pgina anterior respecto al mbito ( 4.1.3) significa que tambin hay siete categoras para la visibilidad de un identificador:sentencia; bloque (o local); funcin; prototipo de funcin; fichero; clase y espacio de nombres. Sin embargo, los ms importantes y usuales son: de funcin; de fichero (global), y de programa. Ejemplo: ... { int i; char ch; i = 3; ... { // auto por defecto // int i y char ch, en mbito y visibles

double i; i = 3.0e3; ch = 'A'; }

i += 1; ... // char ch todava en mbito y visible (ch = 'A') } // int i y char ch son terminados aqu ... // int i y char ch fuera de mbito

// // // // // //

double i en mbito y visible int i=3 en mbito pero oculto char ch en mbito y visible double i es terminada aqu double i fuera de mbito int i visible, i == 4

Respecto a este asunto de la visibilidad, veremos que se aplican reglas especiales para los nombres de clases y miembros ocultos de clase. Bajo ciertas condiciones, los operadores de acceso permiten acceder identificadores ocultos cuando son miembros de clase.

3 Variables locales Las variables locales o de bloque, tienen visibilidad dentro del bloque, desde el punto de declaracin ( 4.1.3) hasta el final del mismo. De este tipo son las variables automticas, incluyendo los parmetros formales de las funciones. Ocultan cualquier otra variable o funcin externas del mismo nombre. Por ejemplo: int x, y; func(double x) { double y; // oculta a int y ... // double y visible desde aqu } // fin de visibilidad de double y 4.1.3 Ocultacin.

Ver tambin

4 Variables globales Las variables globales a un fichero se declaran fuera de cualquier bloque, funcin o clase. Sintcticamente la declaracin es idntica que la de las variables locales, solo cambia la situacin de la declaracin. El hecho de colocarlas al principio evita tener que hacerlas visibles dentro de cada funcin con una declaracin extern de cada variable ( 4.1.8d). La regla es:

Si la declaracin de una variable externa ocurre antes que su uso en alguna funcin particular, entonces no hay necesidad de una declaracin extern de la variable dentro de la funcin.

Ejemplo: extern x; // punto de declaracn de x ... void func1(int y) { x = x+y; // correcto x es visible } void func2(int y) { z = z+y; // incorrecto z no es visible extern z; z = z+y; // correcto z es ahora visible }

4.1 El mbito de una variable global es desde el punto de declaracin hasta el final del fichero, por lo que tradicionalmente se suelen declarar al principio, junto con los prototipos de las funciones, ya que en caso contrario hay que declararlas dentro de cada funcin que las invoque (avisar a cada funcin que la variable en cuestin es externa). Puesto que C++ no permite declaracin de funciones dentro de funciones [1], sus identificadores son globales al fichero en que se han declarado (las funciones tienen mbito global). Lo que s se permite son prototipos de funciones dentro de otras funciones que las invocan (los prototipos son declaraciones, no definiciones). Por supuesto, si las variables globales a un fichero deben ser vistas desde otros ficheros, es necesario declararlas al principio como extern (en los otros ficheros). Por esta razn y por comodidad, se acostumbra a agrupar todas las declaraciones de variables y funciones externas en unos ficheros que actan como "repositorios" de declaraciones y definiciones que son incluidos mediante #include ( 4.9.10g) al principio de cada fuente (as no se olvida ningn "extern"). Por esta razn tales ficheros se denominan "de cabecera". Nota: por una larga tradicin de C, las declaraciones de las funciones de las Libreras Estndar ( 5) se agrupan en una serie de ficheros de nombres conocidos, de los que los correspondientes a las libreras que se mantienen por compatibilidad con el antiguo C tienen la terminacin .h, de "Header" (cabecera en ingls).

Por defecto, las variables externas y las funciones tiene la propiedad de que todas las referencias a sus nombres (incluso desde mdulos compilados separadamente), referencian a la misma entidad, es decir, tienen enlazado externo ( 1.4.4).

4.2 Como se ver a continuacin, todas las variables globales a un fichero y por este simple hecho, tienen duracin esttica. Nota: aunque desde cierta ptica, el empleo de variables globales facilita algunas cosas. Por ejemplo, hay que pasar menos parmetros a las funciones, es mala prctica abusar de ellas, los programas se hacen difciles de manejar e interpretar y existe ms posibilidad de colisiones de nombres (decimos que se "poluciona" el espacio global). Es preferible el estilo en que todos

los datos que se necesitan en una funcin estn definidos dentro del cuerpo o en su lista de parmetros.

4.3 No olvidar que una variable global declarada static ( 4.1.8c) solo es visible desde el punto de declaracin hasta el final del fichero y solo en ese fichero. Esto es tambin de aplicacin para las funciones.

4.1.5 Duracin de almacenamiento y ciclo vital


1 Duracin de almacenamiento La duracin de almacenamiento ("Storage duration") de un objeto, es una propiedad estrechamente relacionada con el tipo de almacenamiento. Se define como el mnimo potencial de vida que tiene el almacenamiento que alberga al objeto, y determina el periodo en el que los objetos pueden tener existencia real, es decir, estar alojados fsicamente en memoria. Esta propiedad acompaa al objeto desde el instante de su creacin (definicin) y depende del modo en que se realiz esta definicin. Existen tres tipos de duracin de almacenamiento: esttica ; local (o automtica) y persistente [2] , cuyas caractersticas describimos a continuacin. ,

1.1 Duracin esttica Tan pronto como se inicia la ejecucin de un programa, los objetos con duracin esttica reciben su correspondiente asignacin de memoria [1], que permanece hasta que finaliza el programa. Si no existe ningn iniciador o constructor explcito, estos objetos son inicializados a cero o nulo ( 4.1.2). Nota: el Estndar establece que los objetos que no tengan ninguna de las otras duraciones (local o persistente) son de duracin esttica.

Es importante no confundir el concepto de duracin esttica con visibilidad global o de fichero, dado que un objeto puede tener duracin esttica (toda la vida del programa) y mbito local a un bloque de cdigo; a una funcin, o a un fichero. La contraria siempre es equivalente, es decir: una variable, por el simple hecho de tener visibilidad global, tiene duracin esttica. Donde quiera que sean definidas, todas las funciones tienen duracin esttica (porque sus identificadores son globales) y como se ha dicho, todas las variables globales a un fichero tienen duracin esttica por el simple hecho de ser globales. Duracin y visibilidad pueden ser conferidas de forma implcita o explcita. La primera, simplemente declarndolas fuera de cualquier funcin (generalmente al principio del fichero). La declaracin explcita se efecta mediante el uso de los modificadores static ( 4.1.8c) y extern ( 4.1.8d). Nota: no olvidar que (desgraciadamente, en este sentido el estndar ANSI se presta a confusin) la variable o funcin global declaradastatic solo es visible dentro del fichero en que se ha declarado (desde el punto de declaracin hasta el final). Es decir, le resta su posibilidad

ser visible desde otros ficheros. Sin embargo, este uso confuso puede soslayarse porque el mecanismo de espacio de nombres de C++ permite un artificio por el que una variable global a un fichero solo sea visible dentro del mismo sin necesidad de utilizar la palabra static ( 4.1.11b Subespacios annimos).

Los objetos locales de clarados con el especificador static se crean en una zona especial de memoria, el montn o "heap" ( 1.3.2) en el momento en que la ejecucin del programa llega por primera vez a su declaracin. A partir de este momento tienen existencia hasta la finalizacin del programa.

1.2 Duracin automtica Los objetos de duracin local, tambin conocidos como automticos, tienen una existencia ms precaria (que los estticos). Son creados en la pila o en un registro cuando entra en ejecucin el bloque o funcin, y son destruidos automticamente cuando el programa sale del bloque o funcin. C++ dispone de una palabra clave especfica para este fin: auto ( 4.1.8a). Ejemplo: int func(int z) { auto int i; i = 5; int j = 5; return (i+z); } Sin embargo este especificador raramente se usa, ya que es innecesario y redundante, pues auto es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcin, de forma que las variables i y j del ejemplo anterior tienen las mismas propiedades. En los objetos con duracin local, su mbito tambin es local al bloque o funcin. Pero la inversa no es necesariamente cierta, los objetos con mbito local pueden tener duracin no automtica. Cuando una variable automtica sale de su mbito, es llamado implcitamente su destructor. En las variables locales esto ocurre cuando el bloque en que son declaradas deja de estar activo. En las variables globales los destructores son llamados como parte del proceso de salida de la funcinmain. Estos destructores son llamados exactamente en el orden inverso en que fueron llamados sus constructores. Ojo: cuando un puntero a un objeto sale de mbito no es llamado implcitamente ningn destructor para el objeto sealado [4], lo que significa que es necesario utilizar el operador delete para destruir el objeto (salvo que el objeto se destruya a su vez por su cuenta). Ejemplo: { int x = 10; int* pt1 = &x; int* pt2; pt2 = new(int); ... delete pt2; } // // // // L.2 L.3 L.4 L.5 Ok Ok Ok Ok crea crea crea crea un un un un int int* int* int (1)

// L.7: Ok. destruido int(1) *pt2 // L.8: Ok destruidos x, pt1 y pt2

Los objetos de duracin local deben ser iniciados explcitamente, de otro modo su contenido es imprevisible (simplemente basura) [3]. Aunque pueden ser declarados explcitamente con el modificador auto, hemos sealado que es innecesario, ya que este es el tipo asignado por defecto a las variables declaradas dentro de cualquier bloque o funcin. Nota: cuando se aplica el especificador de almacenamiento register ( 4.1.8b) a la declaracin de variables (por ejemplo, int, char, float), adems de pasar una peticin al compilador para que, caso de ser posible, site el objeto en un registro, implica tambin duracin automtica (auto).

1.3 Duracin persistente Los objetos persistentes (tambin llamados dinmicos) son creados y destruidos por llamadas a funciones especficas. Son creados en una reserva especial de memoria conocida como montn (heap 1.3.2) utilizando cualquier funcin de librera estndar como malloc o el operadornew ( 4.9.20). La destruccin debe realizarse explcitamente con free o delete ( 4.9.21). An a riesgo de ser pelmazos, es importante insistir en que, salvo que se adopten medidas especiales, la destruccin de los objetos persistentes se realiza siempre mediante la utilizacin explcita (por el programador) de las funciones mencionadas. Recordar que con estos objetos no ocurre lo mismo que con los automticos . En aquellos la nica preocupacin del programador es crearlos, ya que al salir de mbito sern automticamente destruidos por el compilador. Estos en cambio, deben ser destruidos explcitamente.

2 Ciclo vital El tiempo de vida o ciclo vital ("Lifetime") de un objeto es una propiedad de tiempo de ejecucin ("Runtime"). Viene determinado por el lapso entre su creacin y su destruccin. Por supuesto no puede exceder la duracin de su almacenamiento. El ciclo vital comienza cuando se le asigna espacio de almacenamiento y, si no es un objeto trivial, cuando el objeto es convenientemente iniciado por su constructor. Finaliza cuando es llamado el destructor o se rehsa la zona de almacenamiento que le haba sido asignada. Nota: decimos que un objeto es trivial cuando es, por ejemplo, un tipo simple preconstruido en el lenguaje. En este caso una expresin del tipo int x; basta para que el compilador pueda reservar espacio de almacenamiento.

Observe que el ciclo vital de los objetos automticos y estticos es controlado automticamente por el compilador. En los primeros la destruccin se realiza cuando el objeto sale de mbito. En los segundos la destruccin ocurre con las rutinas de finalizacin del programa. Por su parte el ciclo vital de los objetos dinmicos es controlado por el programador. 469

You might also like